util 0.4.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.
- checksums.yaml +7 -0
- data/.yardopts +1 -0
- data/CECILL-C.EN +517 -0
- data/CECILL-C.FR +521 -0
- data/LICENSES.md +21 -0
- data/README.md +478 -0
- data/lib/util.rb +12 -0
- data/lib/util/args.rb +138 -0
- data/lib/util/communia.rb +8 -0
- data/lib/util/console_logger.rb +178 -0
- data/lib/util/downloader.rb +157 -0
- data/lib/util/i18n.rb +327 -0
- data/lib/util/lists.rb +6 -0
- data/lib/util/lists/iso639.rb +149 -0
- data/lib/util/result.rb +175 -0
- data/lib/util/test.rb +225 -0
- data/lib/util/yaml.rb +18 -0
- data/share/lists/iso639-3.yml +35528 -0
- data/test/unit.rb +20 -0
- data/test/unit/args.rb +22 -0
- data/test/unit/downloader.rb +145 -0
- data/test/unit/downloader/orig/simple.html +7 -0
- data/test/unit/i18n.rb +216 -0
- data/test/unit/i18n/CamelCase/eng.yml +2 -0
- data/test/unit/i18n/CamelCase/fra.yml +2 -0
- data/test/unit/i18n/aaj.yml +2 -0
- data/test/unit/i18n/en.yml +2 -0
- data/test/unit/i18n/fra.yml +2 -0
- data/test/unit/i18n/i18n +0 -0
- data/test/unit/i18n/prv.yml +2 -0
- data/test/unit/i18n/void/fra.yml/Yes-git-I-need-this-folder-even-if-it-is-empty +0 -0
- data/test/unit/i18n//316/261/316/273/316/271/316/261/317/202/fra.yml +2 -0
- data/test/unit/lists/iso639.rb +78 -0
- data/test/unit/result.rb +180 -0
- data/tools/create-iso639-3.rb +235 -0
- metadata +80 -0
data/lib/util.rb
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
require 'util/args'
|
|
2
|
+
require 'util/communia'
|
|
3
|
+
require 'util/console_logger'
|
|
4
|
+
require 'util/downloader'
|
|
5
|
+
require 'util/i18n'
|
|
6
|
+
require 'util/lists'
|
|
7
|
+
require 'util/result'
|
|
8
|
+
require 'util/test'
|
|
9
|
+
require 'util/yaml'
|
|
10
|
+
|
|
11
|
+
# A collection of simple utilities to reduce boilerplate.
|
|
12
|
+
module Util; end
|
data/lib/util/args.rb
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
module Util
|
|
2
|
+
# Functions to typecheck the arguments of a function.
|
|
3
|
+
class Args
|
|
4
|
+
private_class_method :new
|
|
5
|
+
|
|
6
|
+
# If no alternative value is provided to {check}, these will be used.
|
|
7
|
+
DEFAULT_VALUES = {
|
|
8
|
+
Array => [],
|
|
9
|
+
'Boolean' => false,
|
|
10
|
+
Class => NilClass,
|
|
11
|
+
Complex => 0.to_c,
|
|
12
|
+
Encoding => Encoding::UTF_8,
|
|
13
|
+
FalseClass => true,
|
|
14
|
+
Float => 0.0,
|
|
15
|
+
Hash => {},
|
|
16
|
+
Integer => 0,
|
|
17
|
+
Module => Kernel,
|
|
18
|
+
NilClass => nil,
|
|
19
|
+
Object => Object.new,
|
|
20
|
+
Queue => Queue.new,
|
|
21
|
+
Random => Random::DEFAULT,
|
|
22
|
+
Range => (0..),
|
|
23
|
+
Rational => 0.to_r,
|
|
24
|
+
Regexp => /.*/,
|
|
25
|
+
SizedQueue => SizedQueue.new(1),
|
|
26
|
+
String => '',
|
|
27
|
+
Symbol => :nil,
|
|
28
|
+
Time => Time.now,
|
|
29
|
+
TrueClass => false,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# @no_doc
|
|
33
|
+
FUNCTIONS = {
|
|
34
|
+
Array => :to_a,
|
|
35
|
+
Complex => :to_c,
|
|
36
|
+
Enumerator => :to_enum,
|
|
37
|
+
Float => :to_f,
|
|
38
|
+
Hash => :to_h,
|
|
39
|
+
Integer => :to_i,
|
|
40
|
+
Rational => :to_r,
|
|
41
|
+
String => :to_s,
|
|
42
|
+
Symbol => :to_sym,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
# Verify whether a given argument or arguments belong to a class or can
|
|
46
|
+
# be converted into that class. Any number of sequences of the three
|
|
47
|
+
# arguments below can be passed.
|
|
48
|
+
# @param [Object] value argument to check
|
|
49
|
+
# @param [Class, String] klass class to which it must belong; Boolean is
|
|
50
|
+
# a synonym for TrueClass; all standard classes who have #to_X will try
|
|
51
|
+
# to convert the value if it responds to the given conversion method
|
|
52
|
+
# (if not provided, +NilClass+ is used)
|
|
53
|
+
# @param [Object] alt value to use if the argument does not belong to the
|
|
54
|
+
# wanted class (if not provided, will default to +DEFAULT_VALUES[klass]+)
|
|
55
|
+
# @return [Object, Array<Object>] an array of the checked and converted
|
|
56
|
+
# values, or just the value if the array has only one element
|
|
57
|
+
# @example
|
|
58
|
+
# def create_integer_hash key, value
|
|
59
|
+
# key, value = Util::Args.check key, Symbol, :def, value, Integer, nil
|
|
60
|
+
# { key => value }
|
|
61
|
+
# end
|
|
62
|
+
#
|
|
63
|
+
# hash1 = create_integer_hash 'hello', 13.4 # { :hello => 13 }
|
|
64
|
+
# hash2 = create_integer_hash nil, nil # { :def => nil }
|
|
65
|
+
def self.check *args
|
|
66
|
+
check_internal nil, *args
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Typecheck the content of an options hash, while ignoring undefined
|
|
70
|
+
# options. Calls Args.check on the values associated with a given key,
|
|
71
|
+
# according to the rest of the informations given.
|
|
72
|
+
# @param [Hash] opts hash whose content to check
|
|
73
|
+
# @param [Array] args see {check} for the rest of the arguments
|
|
74
|
+
# @return (see check)
|
|
75
|
+
# @note It is not necessary to check whether +opts+ is a +Hash+, the
|
|
76
|
+
# method will do it.
|
|
77
|
+
# @example
|
|
78
|
+
# def initialize opts={}
|
|
79
|
+
# @encoding, @font_size, @line_height = Util::Args.check_opts opts, \
|
|
80
|
+
# :enc, String, 'UTF-8', :size, Integer, 12, :height, Float, 1.0
|
|
81
|
+
# end
|
|
82
|
+
def self.check_opts opts, *args
|
|
83
|
+
check_internal opts, *args
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
private
|
|
87
|
+
|
|
88
|
+
# Common parts to both {check} and {check_opts}.
|
|
89
|
+
def self.check_internal opts, *args
|
|
90
|
+
return nil if args.length == 0
|
|
91
|
+
opts = check opts, Hash, {} unless opts.nil?
|
|
92
|
+
count, modulo = args.length.divmod 3
|
|
93
|
+
|
|
94
|
+
if modulo == 1 then
|
|
95
|
+
args << NilClass
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
if modulo > 0 then
|
|
99
|
+
count += 1
|
|
100
|
+
args << DEFAULT_VALUES[args.last]
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
res = []
|
|
104
|
+
(0...count).each do |i|
|
|
105
|
+
value, klass, alt = args[i*3], args[i*3+1], args[i*3+2]
|
|
106
|
+
value = opts[value] unless opts.nil?
|
|
107
|
+
res << alt and next if value.nil?
|
|
108
|
+
|
|
109
|
+
if FUNCTIONS.has_key? klass then
|
|
110
|
+
f = FUNCTIONS[klass]
|
|
111
|
+
res << (value.respond_to?(f) ? value.send(f) : alt)
|
|
112
|
+
next
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
case klass.to_s
|
|
116
|
+
when 'Boolean' then res << (value ? true : alt) and next
|
|
117
|
+
when 'FalseClass' then res << (value ? alt : false) and next
|
|
118
|
+
when 'TrueClass' then res << (value ? true : alt) and next
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
res << alt and next unless klass.is_a?(Class) and value.is_a?(klass)
|
|
122
|
+
res << value
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
(res.length < 2) ? res.first : res
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Alias for {Args.check_opts}
|
|
130
|
+
class Opts
|
|
131
|
+
private_class_method :new
|
|
132
|
+
|
|
133
|
+
# Alias for {Args.check_opts}
|
|
134
|
+
def self.check opts, *args
|
|
135
|
+
Args.check_opts opts, *args
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
module Util
|
|
2
|
+
# Help write formatted messages to the console, for friendlier
|
|
3
|
+
# command-line interface. Uses generally available ANSI codes, so
|
|
4
|
+
# it should work on all UNIXes and on recent Windows.
|
|
5
|
+
#
|
|
6
|
+
# @example
|
|
7
|
+
# cl = ConsoleLogger.new e: { :stderr => true }
|
|
8
|
+
# cl.warning 'Errors will be logged on STDERR.'
|
|
9
|
+
# # Message written in yellow
|
|
10
|
+
# begin
|
|
11
|
+
# text = File.read 'secret.msg'
|
|
12
|
+
# rescue Exception => e
|
|
13
|
+
# msg = 'Cannot go any further because of %E%, aborting.'
|
|
14
|
+
# cl.error msg, 'E': e.message
|
|
15
|
+
# # Message written in red
|
|
16
|
+
# end
|
|
17
|
+
class ConsoleLogger
|
|
18
|
+
require 'util/args'
|
|
19
|
+
|
|
20
|
+
# ANSI code to reset all formatting
|
|
21
|
+
RESET = "\x1b[0m"
|
|
22
|
+
# @no_doc
|
|
23
|
+
BASE = "\x1b[%CODE%m"
|
|
24
|
+
# @no_doc
|
|
25
|
+
COLORS = { :black => 0, :red => 1, :green => 2, :yellow => 3,
|
|
26
|
+
:blue => 4, :magenta => 5, :cyan => 6, :white => 7 }
|
|
27
|
+
# @no_doc
|
|
28
|
+
COLOR_TYPES = { :fg => 30, :bg => 40, :bright => 60 }
|
|
29
|
+
# @no_doc
|
|
30
|
+
DECORS = { :bold => 1, :faint => 2, :italic => 3, :underline => 4,
|
|
31
|
+
:blink => 5, :reverse => 7, :conceal => 8, :crossed => 9,
|
|
32
|
+
:dbl_underline => 21, :overline => 53 }
|
|
33
|
+
# @no_doc
|
|
34
|
+
CL = ConsoleLogger
|
|
35
|
+
|
|
36
|
+
# Generate the ANSI code to obtain a given formatting.
|
|
37
|
+
# @param opts [Hash] the wanted formatting
|
|
38
|
+
# @option opts [:black, :blue, :cyan, :green, :magenta,
|
|
39
|
+
# :red, :white, :yellow] :color font color
|
|
40
|
+
# @option opts [idem] :bgcolor background color
|
|
41
|
+
# @option opts [Boolean] :bright use bright font color
|
|
42
|
+
# @option opts [Boolean] :bgbright use bright background color
|
|
43
|
+
# @option opts [:blink, :bold, :conceal, :crossed,
|
|
44
|
+
# :dbl_underline, :faint, :italic, :overline, :reverse,
|
|
45
|
+
# :underline, Array<idem>] :decor text decorations
|
|
46
|
+
def self.escape_code opts={}
|
|
47
|
+
opts = Util::Args.check opts, Hash, {}
|
|
48
|
+
return RESET if opts.empty?
|
|
49
|
+
code = ''
|
|
50
|
+
|
|
51
|
+
if opts.has_key? :color then
|
|
52
|
+
color = Util::Args.check opts[:color], Symbol, :white
|
|
53
|
+
color = :white unless COLORS.has_key? color
|
|
54
|
+
bright = Util::Args.check opts[:bright], 'Boolean', false
|
|
55
|
+
|
|
56
|
+
cur = COLOR_TYPES[:fg] + COLORS[color]
|
|
57
|
+
cur += COLOR_TYPES[:bright] if bright
|
|
58
|
+
code += cur.to_s
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
if opts.has_key? :bgcolor then
|
|
62
|
+
color = Util::Args.check opts[:bgcolor], Symbol, :black
|
|
63
|
+
color = :black unless COLORS.has_key? color
|
|
64
|
+
bright = Util::Args.check opts[:bgbright], 'Boolean', false
|
|
65
|
+
|
|
66
|
+
cur = COLOR_TYPES[:bg] + COLORS[color]
|
|
67
|
+
cur += COLOR_TYPES[:bright] if bright
|
|
68
|
+
code += ';' unless code.empty?
|
|
69
|
+
code += cur.to_s
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
if opts.has_key? :decor then
|
|
73
|
+
decors = Util::Args.check opts[:decor], Array, [opts[:decor]]
|
|
74
|
+
cur = ''
|
|
75
|
+
decors.each do |d|
|
|
76
|
+
cur += ';' + DECORS[d].to_s if DECORS.has_key? d
|
|
77
|
+
end
|
|
78
|
+
cur = cur.sub ';', '' if code.empty?
|
|
79
|
+
code += cur
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
code.empty? ? RESET : BASE.sub('%CODE%', code)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Create a new ConsoleLogger.
|
|
86
|
+
# @param config [Hash] initial configuration: for each kind of
|
|
87
|
+
# message, whether to use STDERR or STDOUT, and which formatting
|
|
88
|
+
# @option config [Hash { :stderr => Boolean, :code => String }]
|
|
89
|
+
# e configuration for error (defaults to red text)
|
|
90
|
+
# @option config [Hash { :stderr => Boolean, :code => String }]
|
|
91
|
+
# i configuration for information (defaults to cyan text)
|
|
92
|
+
# @option config [Hash { :stderr => Boolean, :code => String }]
|
|
93
|
+
# n configuration for normal (defaults to no formatting)
|
|
94
|
+
# @option config [Hash { :stderr => Boolean, :code => String }]
|
|
95
|
+
# o configuration for ok (defaults to green text)
|
|
96
|
+
# @option config [Hash { :stderr => Boolean, :code => String }]
|
|
97
|
+
# w configuration for warning (defaults to yellow text)
|
|
98
|
+
def initialize config={}
|
|
99
|
+
config = Util::Args.check config, Hash, {}
|
|
100
|
+
@config = {
|
|
101
|
+
:e => { :io => $stdout, :code => CL.escape_code(color: :red) },
|
|
102
|
+
:i => { :io => $stdout, :code => CL.escape_code(color: :cyan) },
|
|
103
|
+
:n => { :io => $stdout, :code => '' },
|
|
104
|
+
:o => { :io => $stdout, :code => CL.escape_code(color: :green) },
|
|
105
|
+
:w => { :io => $stdout, :code => CL.escape_code(color: :yellow) },
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
config.each_pair do |k, v|
|
|
109
|
+
next unless @config.has_key? k
|
|
110
|
+
v = Util::Args.check v, Hash, {}
|
|
111
|
+
@config[k][:io] = (v[:stderr] == true) ? $stderr : $stdout
|
|
112
|
+
@config[k][:code] = CL.escape_code v
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Print an error to the console.
|
|
117
|
+
# @param msg [String] message to print
|
|
118
|
+
# @param payload [Hash<#to_s, #to_s>] parts to replace in the base
|
|
119
|
+
# message: '%KEY%' will be replaced by 'VALUE'.
|
|
120
|
+
# @example
|
|
121
|
+
# msg = 'The array contains only %I% objects of type %T%.'
|
|
122
|
+
# cl.error msg, 'T': Float, 'I': arr.how_many?(Float)
|
|
123
|
+
#
|
|
124
|
+
# # Results in `The array contains only 42 objects of type Float.`
|
|
125
|
+
# @return nil
|
|
126
|
+
def error msg, payload={}
|
|
127
|
+
self.printf :e, msg, payload
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Print an important message to the console.
|
|
131
|
+
# @param (see #error)
|
|
132
|
+
# @example (see #error)
|
|
133
|
+
# @return (see #error)
|
|
134
|
+
def important msg, payload={}
|
|
135
|
+
self.printf :i, msg, payload
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Print a normal message to the console.
|
|
139
|
+
# @param (see #error)
|
|
140
|
+
# @example (see #error)
|
|
141
|
+
# @return (see #error)
|
|
142
|
+
def normal msg, payload={}
|
|
143
|
+
self.printf :n, msg, payload
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Print an approval to the console.
|
|
147
|
+
# @param (see #error)
|
|
148
|
+
# @example (see #error)
|
|
149
|
+
# @return (see #error)
|
|
150
|
+
def ok msg, payload={}
|
|
151
|
+
self.printf :o, msg, payload
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Print a warning to the console.
|
|
155
|
+
# @param (see #error)
|
|
156
|
+
# @example (see #error)
|
|
157
|
+
# @return (see #error)
|
|
158
|
+
def warning msg, payload={}
|
|
159
|
+
self.printf :w, msg, payload
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
private
|
|
163
|
+
|
|
164
|
+
# Common parts to all messaging methods.
|
|
165
|
+
# @param type [:e, :i, :n, :o, :w] kind of message
|
|
166
|
+
# @param msg (see #error)
|
|
167
|
+
# @param payload (see #error)
|
|
168
|
+
# @return nil
|
|
169
|
+
def printf type, msg, payload
|
|
170
|
+
msg = Util::Args.check msg, String, ''
|
|
171
|
+
payload = Util::Args.check payload, Hash, {}
|
|
172
|
+
payload.each_pair do |k, v|
|
|
173
|
+
msg = msg.gsub "%#{k}%", v.to_s
|
|
174
|
+
end
|
|
175
|
+
@config[type][:io].puts @config[type][:code] + msg + RESET
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
module Util
|
|
2
|
+
# A helper to safely dowload a file. Can be dowloaded to an actual file,
|
|
3
|
+
# or directly parsed by another gem (e. g. +Nokogiri+).
|
|
4
|
+
# @example
|
|
5
|
+
# require 'oga' # Must be required by the user, `Util` will not do it
|
|
6
|
+
# url = 'https://www.perdu.com/'
|
|
7
|
+
# html = Util::Downloader.new(url).set_dest(Oga)
|
|
8
|
+
# html.download # => Util::Result.ok
|
|
9
|
+
# html.data.at_css('h1').text # 'Perdu sur l\'Internet ?'
|
|
10
|
+
#
|
|
11
|
+
# url = 'https://gitlab.com/uploads/-/system/user/avatar/5582173/avatar.png'
|
|
12
|
+
# Util::Downloader.new(url).set_name('guillel.png').set_force.download
|
|
13
|
+
class Downloader
|
|
14
|
+
attr_reader :data
|
|
15
|
+
attr_reader :dest
|
|
16
|
+
attr_reader :force
|
|
17
|
+
attr_reader :name
|
|
18
|
+
attr_reader :ref
|
|
19
|
+
attr_reader :url
|
|
20
|
+
|
|
21
|
+
# @no_doc
|
|
22
|
+
ALLOWED = [:data, :force, :url]
|
|
23
|
+
# @no_doc
|
|
24
|
+
DEFAULT_OPTIONS = {
|
|
25
|
+
:dest => '.',
|
|
26
|
+
:name => '',
|
|
27
|
+
:ref => '',
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# Create a new helper to safely download a file.
|
|
31
|
+
# @param url [String] URL of the page to download
|
|
32
|
+
# @param opts [#to_h] download options
|
|
33
|
+
# @option opts [String, Class] :dest the directory in which to download,
|
|
34
|
+
# or the class with which to parse it
|
|
35
|
+
# @option opts [Boolean] :force whether to replace an existing file
|
|
36
|
+
# @option opts [String] :name name under which to save the file
|
|
37
|
+
# @option opts [String] :ref referer to use while downloading
|
|
38
|
+
# @return [self]
|
|
39
|
+
def initialize url, opts={}
|
|
40
|
+
require 'util/args'
|
|
41
|
+
@url, opts = Util::Args.check url, String, '', opts, Hash, {}
|
|
42
|
+
opts[:force] === true ? set_force : unset_force
|
|
43
|
+
|
|
44
|
+
DEFAULT_OPTIONS.each_pair do |k, v|
|
|
45
|
+
self.method('set_' + k.to_s).call (opts[k].nil? ? v : opts[k])
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Actually download the file, according to the given options.
|
|
50
|
+
# @return [Util::Result]
|
|
51
|
+
def download
|
|
52
|
+
require 'open-uri'
|
|
53
|
+
require 'util/result'
|
|
54
|
+
|
|
55
|
+
return Util::Result.err :no_url, self if @url.empty?
|
|
56
|
+
@name = File.basename URI(@url).path if @name.empty?
|
|
57
|
+
@name = 'index.html' if @name.empty? or @name == '/'
|
|
58
|
+
|
|
59
|
+
if @dest.is_a?(String) then
|
|
60
|
+
return Util::Result.err :no_dir, self unless File.directory? @dest
|
|
61
|
+
return Util::Result.err :file_exists, self if not @force \
|
|
62
|
+
and File.exists?(File.join @dest, @name)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
begin
|
|
66
|
+
io = @ref.empty? ? URI.open(@url) : URI.open(@url, 'Referer' => @ref)
|
|
67
|
+
case @dest.to_s
|
|
68
|
+
when 'Magick' then @data = Magick::Image.from_blob io.read
|
|
69
|
+
when 'Nokogiri' then @data = Nokogiri::HTML io
|
|
70
|
+
when 'Nokogiri::HTML' then @data = Nokogiri::HTML io
|
|
71
|
+
when 'Nokogiri::XML' then @data = Nokogiri::XML io
|
|
72
|
+
when 'Oga' then @data = Oga.parse_html io
|
|
73
|
+
when 'Oga::HTML' then @data = Oga.parse_html io
|
|
74
|
+
when 'Oga::XML' then @data = Oga.parse_xml io
|
|
75
|
+
when 'REXML' then @data = REXML::Document.new io
|
|
76
|
+
else
|
|
77
|
+
if @dest.respond_to? :parse then
|
|
78
|
+
@data = @dest.parse io
|
|
79
|
+
elsif @dest.respond_to? :read then
|
|
80
|
+
@data = @dest.read io
|
|
81
|
+
else
|
|
82
|
+
IO.copy_stream(io, File.join(@dest, @name))
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
rescue Exception => e
|
|
86
|
+
return Util::Result.err e, self
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
Util::Result.ok
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Return the value of one of the options, the URL, or the parsed web page.
|
|
93
|
+
# @param key [#to_sym] the attribute to read
|
|
94
|
+
# @return [Object] if succesfull
|
|
95
|
+
# @return [nil] if +key+ cannot be converted to a symbol, or is not part
|
|
96
|
+
# of the allowed attributes to read
|
|
97
|
+
def [] key
|
|
98
|
+
require 'util/args'
|
|
99
|
+
key = Util::Args.check key, Symbol, nil
|
|
100
|
+
return nil if key.nil?
|
|
101
|
+
return nil unless (DEFAULT_OPTIONS.keys + ALLOWED).include? key
|
|
102
|
+
instance_variable_get('@' + key.to_s)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Set the directory in which to download the file, or the class with
|
|
106
|
+
# which to parse it. Currently accepted class are the following.
|
|
107
|
+
# - +Magick+ (will try to parse a +Magick::Image+).
|
|
108
|
+
# - +Nokogiri::HTML+ or its alias +Nokogiri+.
|
|
109
|
+
# - +Nokogiri::XML+.
|
|
110
|
+
# - +Oga::HTML+ or its alias +Oga+.
|
|
111
|
+
# - +Oga::XML+.
|
|
112
|
+
# - +REXML+.
|
|
113
|
+
# - Any class that responds to +parse+.
|
|
114
|
+
# - Any class that responds to +read+.
|
|
115
|
+
# Please note that with the last two, the methods are tried in this
|
|
116
|
+
# order, and the result might not be what would be expected, especially
|
|
117
|
+
# if the given method does not accept an +IO+ object.
|
|
118
|
+
# @param dir [Module] path to the directory, or if the file shall not
|
|
119
|
+
# be saved, the class that shall parse it
|
|
120
|
+
# @return [self]
|
|
121
|
+
def set_dest dir=DEFAULT_OPTIONS[:dest]
|
|
122
|
+
@dest = dir.is_a?(Module) ? dir : dir.to_s
|
|
123
|
+
self
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Set {download} to replace the destination file if it already exists.
|
|
127
|
+
# @return [self]
|
|
128
|
+
def set_force
|
|
129
|
+
@force = true
|
|
130
|
+
self
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Set {download} to not replace the destination file if it already exists.
|
|
134
|
+
# @return [self]
|
|
135
|
+
def unset_force
|
|
136
|
+
@force = false
|
|
137
|
+
self
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Set the name under which to save the file. If the given name is
|
|
141
|
+
# empty, defaults to the same name as in the remote location.
|
|
142
|
+
# @param n [String] the file name
|
|
143
|
+
# @return [self]
|
|
144
|
+
def set_name n=DEFAULT_OPTIONS[:name]
|
|
145
|
+
@name = n.to_s
|
|
146
|
+
self
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Set the referer to use while downloading.
|
|
150
|
+
# @param r [String] the referer
|
|
151
|
+
# @return [self]
|
|
152
|
+
def set_ref r=DEFAULT_OPTIONS[:ref]
|
|
153
|
+
@ref = r.to_s
|
|
154
|
+
self
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|