simple-images-downloader 1.1.0 → 1.1.1
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 +4 -0
- data/Gemfile.lock +1 -1
- data/lib/simple_images_downloader/client.rb +10 -0
- data/lib/simple_images_downloader/configuration.rb +42 -12
- data/lib/simple_images_downloader/dispenser.rb +14 -0
- data/lib/simple_images_downloader/downloader.rb +16 -0
- data/lib/simple_images_downloader/errors.rb +3 -0
- data/lib/simple_images_downloader/line.rb +11 -0
- data/lib/simple_images_downloader/runner.rb +7 -0
- data/lib/simple_images_downloader/source_file.rb +12 -0
- data/lib/simple_images_downloader/stringio_to_tempfile.rb +9 -0
- data/lib/simple_images_downloader/validatable/destination_validator.rb +9 -0
- data/lib/simple_images_downloader/validatable/file_accessibility_validator.rb +8 -0
- data/lib/simple_images_downloader/validatable/file_persistance_validator.rb +8 -0
- data/lib/simple_images_downloader/validatable/mime_type_validator.rb +17 -2
- data/lib/simple_images_downloader/validatable/validator.rb +2 -0
- data/lib/simple_images_downloader/validatable.rb +19 -0
- data/lib/simple_images_downloader/version.rb +2 -1
- data/lib/simple_images_downloader.rb +16 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0e7adf857ef1d9f8490a079e5828b6025d0b44a21ec098bfc0012124c61223a9
|
4
|
+
data.tar.gz: 50175489068f5c9c7587b940d0690d335f8787f4e78c3f7ede9b26982b13b1c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e205d6d7feb52617f2d526765dd3b3f82509d5cfc2343ca90dbf966966784fa8099cae222904b245ff338d46f5f38883a648d50914c39ec7d3b285af0c6e61a6
|
7
|
+
data.tar.gz: 2660f410b9d48c4876e48fd387c69ad12707b29fef9e02ccb453331fc557c42249d0311da6f0df9eafe50e894ce23fa50c7260d2a6b4f091664ab3247b8dbcbe
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
## 1.1.1 - 2023-09-30
|
2
|
+
- Fixed setting of mime types from configuration. It was using default values instead of the ones set in the configuration
|
3
|
+
- Added documentation to classes and methods
|
4
|
+
|
1
5
|
## 1.1.0 - 2023-09-30
|
2
6
|
- Add validation of downloaded content over path validation
|
3
7
|
- Add ability to extend mime types from configuration
|
data/Gemfile.lock
CHANGED
@@ -1,11 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module SimpleImagesDownloader
|
4
|
+
# add documentation to this class using YARD
|
5
|
+
|
6
|
+
# Client class
|
7
|
+
# Responsible for opening the URI and handling errors
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# SimpleImagesDownloader::Client.new.open(uri)
|
11
|
+
#
|
4
12
|
class Client
|
5
13
|
def initialize(options = Configuration::REQUEST_OPTIONS)
|
6
14
|
@options = options
|
7
15
|
end
|
8
16
|
|
17
|
+
# @param uri [URI] URI object
|
18
|
+
# @return [StringIO] StringIO object
|
9
19
|
def open(uri)
|
10
20
|
uri.open(@options)
|
11
21
|
rescue OpenURI::HTTPRedirect
|
@@ -1,6 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module SimpleImagesDownloader
|
4
|
+
# Configuration class
|
5
|
+
# @example
|
6
|
+
# SimpleImagesDownloader::Configuration.configure do |config|
|
7
|
+
# config.destination = './images'
|
8
|
+
# config.valid_mime_types = ['image/jpeg', 'image/png']
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# SimpleImagesDownloader::Configuration.destination
|
12
|
+
# # => './images'
|
13
|
+
#
|
14
|
+
# SimpleImagesDownloader::Configuration.valid_mime_types
|
15
|
+
# # => ['image/jpeg', 'image/png']
|
16
|
+
#
|
4
17
|
class Configuration
|
5
18
|
include Singleton
|
6
19
|
|
@@ -17,16 +30,16 @@ module SimpleImagesDownloader
|
|
17
30
|
}.freeze
|
18
31
|
|
19
32
|
# https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types#common_image_file_types
|
20
|
-
|
21
|
-
'image/avif'
|
22
|
-
'image/gif'
|
23
|
-
'image/apng'
|
24
|
-
'image/jpg'
|
25
|
-
'image/jpeg'
|
26
|
-
'image/png'
|
27
|
-
'image/svg+xml'
|
28
|
-
'image/webp'
|
29
|
-
|
33
|
+
DEFAULT_VALID_MIME_TYPES = [
|
34
|
+
'image/avif',
|
35
|
+
'image/gif',
|
36
|
+
'image/apng',
|
37
|
+
'image/jpg',
|
38
|
+
'image/jpeg',
|
39
|
+
'image/png',
|
40
|
+
'image/svg+xml',
|
41
|
+
'image/webp'
|
42
|
+
].freeze
|
30
43
|
|
31
44
|
DEFAULT_DESTINATION = './'
|
32
45
|
|
@@ -34,15 +47,32 @@ module SimpleImagesDownloader
|
|
34
47
|
|
35
48
|
def initialize
|
36
49
|
@destination = DEFAULT_DESTINATION
|
37
|
-
@valid_mime_types =
|
50
|
+
@valid_mime_types = DEFAULT_VALID_MIME_TYPES
|
38
51
|
end
|
39
52
|
|
53
|
+
# Allows to set valid_mime_types to check against allowed mime types
|
54
|
+
#
|
55
|
+
# @param value [Array] Array of valid mime types followed by
|
56
|
+
# RFC 1341 - MIME (Multipurpose Internet Mail Extensions) format
|
57
|
+
# @raise [BaseError] if value is not an Array
|
58
|
+
#
|
40
59
|
def valid_mime_types=(value)
|
41
|
-
raise BaseError, 'valid_mime_types must be an array' unless value.is_a?(Array)
|
60
|
+
raise Errors::BaseError, 'valid_mime_types must be an array' unless value.is_a?(Array)
|
42
61
|
|
43
62
|
@valid_mime_types = value
|
44
63
|
end
|
45
64
|
|
65
|
+
#### Configurable options
|
66
|
+
#
|
67
|
+
# destination: String, default: './', description: 'Destination folder to put downloaded images'
|
68
|
+
# valid_mime_types: Array,
|
69
|
+
# default: [
|
70
|
+
# 'image/avif', 'image/gif', 'image/apng', 'image/jpg',
|
71
|
+
# 'image/jpeg', 'image/png', 'image/svg+xml', 'image/webp'
|
72
|
+
# ], description: 'Valid mime types to download'
|
73
|
+
#
|
74
|
+
# @yield [config] Yields the Configuration object to the block
|
75
|
+
#
|
46
76
|
def self.configure
|
47
77
|
yield instance
|
48
78
|
end
|
@@ -1,18 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module SimpleImagesDownloader
|
4
|
+
# Dispenser class
|
5
|
+
# Responsible for moving tempfile to destination directory
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# SimpleImagesDownloader::Dispenser.new(tempfile, 'https://example.com/image.jpg').place
|
9
|
+
#
|
4
10
|
class Dispenser
|
5
11
|
extend Forwardable
|
6
12
|
include Validatable
|
7
13
|
|
8
14
|
def_delegator 'SimpleImagesDownloader::Configuration', :destination, :destination_dir
|
9
15
|
|
16
|
+
# @param source [Tempfile] Tempfile object
|
17
|
+
# @param remote_path [String] original path of the image from input of SimpleImagesDownloader module
|
18
|
+
# @param validators [Array] array of validators for validating the destination directory.
|
19
|
+
# Default: [DestinationValidator.new]
|
10
20
|
def initialize(source, remote_path, validators = [DestinationValidator.new])
|
11
21
|
@source = source
|
12
22
|
@remote_path = remote_path
|
13
23
|
@validators = validators
|
14
24
|
end
|
15
25
|
|
26
|
+
# Moves tempfile to destination directory
|
27
|
+
#
|
28
|
+
# @raise [Errors::BadDestination] if destination directory is not valid
|
29
|
+
# @see DestinationValidator
|
16
30
|
def place
|
17
31
|
validate!({ path: destination_dir })
|
18
32
|
|
@@ -1,15 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module SimpleImagesDownloader
|
4
|
+
# Downloader class
|
5
|
+
# Responsible for downloading images from URI and placing them to the destination folder
|
6
|
+
# allows to use custom client and validators for downloading
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# SimpleImagesDownloader::Downloader.new(uri).download
|
10
|
+
#
|
4
11
|
class Downloader
|
5
12
|
include Validatable
|
6
13
|
|
14
|
+
# @param uri [URI] URI object from which image will be downloaded
|
15
|
+
# @param client [Client] Client object for opening the URI. Default: Client.new
|
16
|
+
# @param validators [Array] array of validators for validating the response. Default: [MimeTypeValidator.new]
|
7
17
|
def initialize(uri, client = Client.new, validators = [MimeTypeValidator.new])
|
8
18
|
@uri = uri
|
9
19
|
@client = client
|
10
20
|
@validators = validators
|
11
21
|
end
|
12
22
|
|
23
|
+
# Downloads image from URI and places it to the destination folder
|
24
|
+
#
|
25
|
+
# @raise [Errors::EmptyResponse] if response is empty
|
26
|
+
# @raise [Errors::BadMimeType] if response is not an image
|
27
|
+
# @see Errors module
|
28
|
+
# @see MimeTypeValidator
|
13
29
|
def download
|
14
30
|
puts "Downloading #{@uri}"
|
15
31
|
|
@@ -1,11 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module SimpleImagesDownloader
|
4
|
+
# Line class
|
5
|
+
# Responsible for parsing the string into URI object
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# SimpleImagesDownloader::Line.new('https://example.com/image.jpg').uri
|
9
|
+
# # => #<URI::HTTPS https://example.com/image.jpg>
|
10
|
+
#
|
4
11
|
class Line
|
5
12
|
def initialize(string)
|
6
13
|
@string = string
|
7
14
|
end
|
8
15
|
|
16
|
+
# @return [URI] URI object
|
17
|
+
# @raise [Errors::BadUrl] if string is not a valid URI
|
18
|
+
# @see Errors::BadUrl
|
19
|
+
#
|
9
20
|
def uri
|
10
21
|
URI.parse(@string)
|
11
22
|
rescue URI::Error
|
@@ -1,7 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module SimpleImagesDownloader
|
4
|
+
# Runner class
|
5
|
+
# Responsible for invoking interface to download images from file
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# SimpleImagesDownloader::Runner.invoke('./urls.txt')
|
9
|
+
#
|
4
10
|
class Runner
|
11
|
+
# Allows to invoke interface to download images from file
|
5
12
|
def self.invoke
|
6
13
|
raise SimpleImagesDownloader::Errors::MissingFileArgumentError if ARGV.size.zero?
|
7
14
|
|
@@ -1,14 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module SimpleImagesDownloader
|
4
|
+
# SourceFile class
|
5
|
+
# Responsible for opening the file of URLs and validating it
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# SimpleImagesDownloader::SourceFile.new('./urls.txt').each_line do |line|
|
9
|
+
# puts line
|
10
|
+
# end
|
11
|
+
#
|
4
12
|
class SourceFile
|
5
13
|
include Validatable
|
6
14
|
|
15
|
+
# @param path [String] path to file
|
16
|
+
# @param validators [Array] array of validators
|
7
17
|
def initialize(path, validators = [FilePersistanceValidator.new, FileAccessibilityValidator.new])
|
8
18
|
@path = path
|
9
19
|
@validators = validators
|
10
20
|
end
|
11
21
|
|
22
|
+
# @yield [line] passes each line of file to block
|
23
|
+
# @yieldparam line [String] line of file
|
12
24
|
def each_line(&block)
|
13
25
|
validate!({ path: @path })
|
14
26
|
|
@@ -1,9 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module SimpleImagesDownloader
|
4
|
+
# StringIOToTempfile module
|
5
|
+
# Responsible for converting StringIO to Tempfile
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# SimpleImagesDownloader::StringioToTempfile.convert(stringio)
|
9
|
+
# # => #<Tempfile:0x00007f9b9c0b3a38>
|
10
|
+
#
|
4
11
|
module StringioToTempfile
|
5
12
|
module_function
|
6
13
|
|
14
|
+
# @param stringio [StringIO] StringIO object
|
15
|
+
# @return [Tempfile] Tempfile object
|
7
16
|
def convert(stringio)
|
8
17
|
tempfile = Tempfile.new(binmode: true)
|
9
18
|
|
@@ -2,7 +2,16 @@
|
|
2
2
|
|
3
3
|
module SimpleImagesDownloader
|
4
4
|
module Validatable
|
5
|
+
# DestinationValidator class
|
6
|
+
# Responsible for validating destination path
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# SimpleImagesDownloader::DestinationValidator.new.validate({ path: './images' })
|
10
|
+
#
|
5
11
|
class DestinationValidator < Validator
|
12
|
+
# @param options [Hash] hash with path to destination directory
|
13
|
+
# @raise [Errors::DestinationIsNotDirectory] if destination is not directory
|
14
|
+
# @raise [Errors::DestinationIsNotWritable] if destination is not writable
|
6
15
|
def validate(options)
|
7
16
|
path = options[:path]
|
8
17
|
|
@@ -2,7 +2,15 @@
|
|
2
2
|
|
3
3
|
module SimpleImagesDownloader
|
4
4
|
module Validatable
|
5
|
+
# FileAccessibilityValidator class
|
6
|
+
# Responsible for validating file accessibility
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# SimpleImagesDownloader::FileAccessibilityValidator.new.validate({ path: './urls.txt' })
|
10
|
+
#
|
5
11
|
class FileAccessibilityValidator < Validator
|
12
|
+
# @param options [Hash] hash with path to file
|
13
|
+
# @raise [Errors::PermissionsError] if file is not readable
|
6
14
|
def validate(options)
|
7
15
|
return if File.readable?(options[:path])
|
8
16
|
|
@@ -2,7 +2,15 @@
|
|
2
2
|
|
3
3
|
module SimpleImagesDownloader
|
4
4
|
module Validatable
|
5
|
+
# FilePersistanceValidator class
|
6
|
+
# Responsible for validating file persistance
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# SimpleImagesDownloader::FilePersistanceValidator.new.validate({ path: './urls.txt' })
|
10
|
+
#
|
5
11
|
class FilePersistanceValidator < Validator
|
12
|
+
# @param options [Hash] hash with path to file
|
13
|
+
# @raise [Errors::MissingFileError] if file does not exist
|
6
14
|
def validate(options)
|
7
15
|
return if File.exist?(options[:path])
|
8
16
|
|
@@ -2,25 +2,40 @@
|
|
2
2
|
|
3
3
|
module SimpleImagesDownloader
|
4
4
|
module Validatable
|
5
|
+
# MimeTypeValidator class
|
6
|
+
# Responsible for validating mime type of file
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# SimpleImagesDownloader::MimeTypeValidator.new.validate({ path: './image.jpg', io: StringIO.new })
|
10
|
+
#
|
5
11
|
class MimeTypeValidator < Validator
|
6
12
|
extend Forwardable
|
7
13
|
|
8
14
|
def_delegator 'SimpleImagesDownloader::Configuration', :valid_mime_types, :valid_mime_types
|
9
15
|
|
16
|
+
# Validates mime type of file. The mime types are taken from file Configuration
|
17
|
+
#
|
18
|
+
# @param options [Hash] hash with path to file and io object. Example: { path: './image.jpg', io: StringIO }
|
19
|
+
# @raise [Errors::BadMimeType] if mime type is not valid
|
20
|
+
# @see Configuration::DEFAULT_VALID_MIME_TYPES to see default valid mime types or add your own
|
10
21
|
def validate(options)
|
11
22
|
path = options[:path]
|
12
23
|
io = options[:io]
|
13
24
|
|
14
25
|
mime_type = mime_type_of(io)
|
15
26
|
|
16
|
-
return if Configuration
|
27
|
+
return if SimpleImagesDownloader::Configuration.valid_mime_types.include?(mime_type)
|
17
28
|
|
18
29
|
raise Errors::BadMimeType.new(path, mime_type)
|
19
30
|
end
|
20
31
|
|
21
32
|
private
|
22
33
|
|
23
|
-
#
|
34
|
+
# Returns mime type of file. Uses UNIX file command
|
35
|
+
#
|
36
|
+
# @see https://github.com/shrinerb/shrine/blob/master/lib/shrine/plugins/determine_mime_type.rb#L94
|
37
|
+
# @param io [IO] io object
|
38
|
+
# @return [String] mime type of file
|
24
39
|
def mime_type_of(io)
|
25
40
|
Open3.popen3('file --mime-type --brief -') do |stdin, stdout, stderr, thread|
|
26
41
|
copy_stream(from: io, to: stdin.binmode)
|
@@ -1,7 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module SimpleImagesDownloader
|
4
|
+
# Validatable module
|
5
|
+
# Responsible for validating the object using array of validators
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# class SourceFile
|
9
|
+
# include Validatable
|
10
|
+
#
|
11
|
+
# def initialize(path, validators = [FilePersistanceValidator.new, FileAccessibilityValidator.new])
|
12
|
+
# @path = path
|
13
|
+
# @validators = validators
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# def each_line(&block)
|
17
|
+
# validate!({ path: @path })
|
18
|
+
# # ...
|
19
|
+
# end
|
20
|
+
# end
|
4
21
|
module Validatable
|
22
|
+
# @param value [Object] value to validate
|
23
|
+
# @raise [Errors::<Particular>Error] if value is not valid
|
5
24
|
def validate!(value)
|
6
25
|
(@validators ||= []).each { |validator| validator.validate(value) }
|
7
26
|
end
|
@@ -25,15 +25,31 @@ require_relative 'simple_images_downloader/downloader'
|
|
25
25
|
require_relative 'simple_images_downloader/strategies/from_file_strategy'
|
26
26
|
require_relative 'simple_images_downloader/strategies/from_url_strategy'
|
27
27
|
|
28
|
+
# SimpleImagesDownloader module
|
29
|
+
# It is a main module of the gem
|
30
|
+
# It is responsible for providing interface to download images from file or url
|
31
|
+
#
|
32
|
+
# @example
|
33
|
+
# SimpleImagesDownloader.from_file('./urls.txt')
|
34
|
+
# SimpleImagesDownloader.from_url('https://example.com/image.jpg')
|
35
|
+
#
|
28
36
|
module SimpleImagesDownloader
|
37
|
+
# Downloads images from file by taking urls from it. Places images to the destination folder set in configuration
|
38
|
+
#
|
39
|
+
# @param path [String] path to file with urls
|
29
40
|
def self.from_file(path)
|
30
41
|
SimpleImagesDownloader::Strategies::FromFileStrategy.new(path).process
|
31
42
|
end
|
32
43
|
|
44
|
+
# Downloads image from url. Places image to the destination folder set in configuration
|
45
|
+
#
|
46
|
+
# @param url [String] url of image
|
33
47
|
def self.from_url(url)
|
34
48
|
SimpleImagesDownloader::Strategies::FromUrlStrategy.new(url).process
|
35
49
|
end
|
36
50
|
|
51
|
+
# Returns root path of the gem. It is used for testing purposes
|
52
|
+
# @return [String] root path of the gem
|
37
53
|
def self.root
|
38
54
|
File.dirname __dir__
|
39
55
|
end
|