scnr-ethon 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +379 -0
  3. data/LICENSE +20 -0
  4. data/README.md +118 -0
  5. data/ethon.gemspec +29 -0
  6. data/lib/ethon/curl.rb +90 -0
  7. data/lib/ethon/curls/classes.rb +65 -0
  8. data/lib/ethon/curls/codes.rb +122 -0
  9. data/lib/ethon/curls/constants.rb +80 -0
  10. data/lib/ethon/curls/form_options.rb +37 -0
  11. data/lib/ethon/curls/functions.rb +58 -0
  12. data/lib/ethon/curls/infos.rb +151 -0
  13. data/lib/ethon/curls/messages.rb +19 -0
  14. data/lib/ethon/curls/options.rb +503 -0
  15. data/lib/ethon/curls/settings.rb +12 -0
  16. data/lib/ethon/easy/callbacks.rb +149 -0
  17. data/lib/ethon/easy/debug_info.rb +47 -0
  18. data/lib/ethon/easy/features.rb +31 -0
  19. data/lib/ethon/easy/form.rb +107 -0
  20. data/lib/ethon/easy/header.rb +61 -0
  21. data/lib/ethon/easy/http/actionable.rb +157 -0
  22. data/lib/ethon/easy/http/custom.rb +29 -0
  23. data/lib/ethon/easy/http/delete.rb +25 -0
  24. data/lib/ethon/easy/http/get.rb +24 -0
  25. data/lib/ethon/easy/http/head.rb +24 -0
  26. data/lib/ethon/easy/http/options.rb +24 -0
  27. data/lib/ethon/easy/http/patch.rb +24 -0
  28. data/lib/ethon/easy/http/post.rb +26 -0
  29. data/lib/ethon/easy/http/postable.rb +32 -0
  30. data/lib/ethon/easy/http/put.rb +27 -0
  31. data/lib/ethon/easy/http/putable.rb +25 -0
  32. data/lib/ethon/easy/http.rb +68 -0
  33. data/lib/ethon/easy/informations.rb +116 -0
  34. data/lib/ethon/easy/mirror.rb +36 -0
  35. data/lib/ethon/easy/operations.rb +65 -0
  36. data/lib/ethon/easy/options.rb +50 -0
  37. data/lib/ethon/easy/params.rb +29 -0
  38. data/lib/ethon/easy/queryable.rb +154 -0
  39. data/lib/ethon/easy/response_callbacks.rb +136 -0
  40. data/lib/ethon/easy/util.rb +28 -0
  41. data/lib/ethon/easy.rb +315 -0
  42. data/lib/ethon/errors/ethon_error.rb +9 -0
  43. data/lib/ethon/errors/global_init.rb +13 -0
  44. data/lib/ethon/errors/invalid_option.rb +13 -0
  45. data/lib/ethon/errors/invalid_value.rb +13 -0
  46. data/lib/ethon/errors/multi_add.rb +12 -0
  47. data/lib/ethon/errors/multi_fdset.rb +12 -0
  48. data/lib/ethon/errors/multi_remove.rb +12 -0
  49. data/lib/ethon/errors/multi_timeout.rb +13 -0
  50. data/lib/ethon/errors/select.rb +13 -0
  51. data/lib/ethon/errors.rb +17 -0
  52. data/lib/ethon/libc.rb +21 -0
  53. data/lib/ethon/loggable.rb +59 -0
  54. data/lib/ethon/multi/operations.rb +228 -0
  55. data/lib/ethon/multi/options.rb +117 -0
  56. data/lib/ethon/multi/stack.rb +49 -0
  57. data/lib/ethon/multi.rb +126 -0
  58. data/lib/ethon/version.rb +6 -0
  59. data/lib/ethon.rb +36 -0
  60. metadata +117 -0
data/lib/ethon/easy.rb ADDED
@@ -0,0 +1,315 @@
1
+ # frozen_string_literal: true
2
+ require 'ethon/easy/informations'
3
+ require 'ethon/easy/features'
4
+ require 'ethon/easy/callbacks'
5
+ require 'ethon/easy/options'
6
+ require 'ethon/easy/header'
7
+ require 'ethon/easy/util'
8
+ require 'ethon/easy/params'
9
+ require 'ethon/easy/form'
10
+ require 'ethon/easy/http'
11
+ require 'ethon/easy/operations'
12
+ require 'ethon/easy/response_callbacks'
13
+ require 'ethon/easy/debug_info'
14
+ require 'ethon/easy/mirror'
15
+
16
+ module Ethon
17
+
18
+ # This is the class representing the libcurl easy interface
19
+ # See http://curl.haxx.se/libcurl/c/libcurl-easy.html for more informations.
20
+ #
21
+ # @example You can access the libcurl easy interface through this class, every request is based on it. The simplest setup looks like that:
22
+ #
23
+ # e = Ethon::Easy.new(url: "www.example.com")
24
+ # e.perform
25
+ # #=> :ok
26
+ #
27
+ # @example You can the reuse this Easy for the next request:
28
+ #
29
+ # e.reset # reset easy handle
30
+ # e.url = "www.google.com"
31
+ # e.followlocation = true
32
+ # e.perform
33
+ # #=> :ok
34
+ #
35
+ # @see initialize
36
+ class Easy
37
+ include Ethon::Easy::Informations
38
+ include Ethon::Easy::Callbacks
39
+ include Ethon::Easy::Options
40
+ include Ethon::Easy::Header
41
+ include Ethon::Easy::Http
42
+ include Ethon::Easy::Operations
43
+ include Ethon::Easy::ResponseCallbacks
44
+ extend Ethon::Easy::Features
45
+
46
+ # Returns the curl return code.
47
+ #
48
+ # @return [ Symbol ] The return code.
49
+ # * :ok: All fine. Proceed as usual.
50
+ # * :unsupported_protocol: The URL you passed to libcurl used a
51
+ # protocol that this libcurl does not support. The support
52
+ # might be a compile-time option that you didn't use, it can
53
+ # be a misspelled protocol string or just a protocol
54
+ # libcurl has no code for.
55
+ # * :failed_init: Very early initialization code failed. This
56
+ # is likely to be an internal error or problem, or a
57
+ # resource problem where something fundamental couldn't
58
+ # get done at init time.
59
+ # * :url_malformat: The URL was not properly formatted.
60
+ # * :not_built_in: A requested feature, protocol or option
61
+ # was not found built-in in this libcurl due to a build-time
62
+ # decision. This means that a feature or option was not enabled
63
+ # or explicitly disabled when libcurl was built and in
64
+ # order to get it to function you have to get a rebuilt libcurl.
65
+ # * :couldnt_resolve_proxy: Couldn't resolve proxy. The given
66
+ # proxy host could not be resolved.
67
+ # * :couldnt_resolve_host: Couldn't resolve host. The given remote
68
+ # host was not resolved.
69
+ # * :couldnt_connect: Failed to connect() to host or proxy.
70
+ # * :ftp_weird_server_reply: After connecting to a FTP server,
71
+ # libcurl expects to get a certain reply back. This error
72
+ # code implies that it got a strange or bad reply. The given
73
+ # remote server is probably not an OK FTP server.
74
+ # * :remote_access_denied: We were denied access to the resource
75
+ # given in the URL. For FTP, this occurs while trying to
76
+ # change to the remote directory.
77
+ # * :ftp_accept_failed: While waiting for the server to connect
78
+ # back when an active FTP session is used, an error code was
79
+ # sent over the control connection or similar.
80
+ # * :ftp_weird_pass_reply: After having sent the FTP password to
81
+ # the server, libcurl expects a proper reply. This error code
82
+ # indicates that an unexpected code was returned.
83
+ # * :ftp_accept_timeout: During an active FTP session while
84
+ # waiting for the server to connect, the CURLOPT_ACCEPTTIMOUT_MS
85
+ # (or the internal default) timeout expired.
86
+ # * :ftp_weird_pasv_reply: libcurl failed to get a sensible result
87
+ # back from the server as a response to either a PASV or a
88
+ # EPSV command. The server is flawed.
89
+ # * :ftp_weird_227_format: FTP servers return a 227-line as a response
90
+ # to a PASV command. If libcurl fails to parse that line,
91
+ # this return code is passed back.
92
+ # * :ftp_cant_get_host: An internal failure to lookup the host used
93
+ # for the new connection.
94
+ # * :ftp_couldnt_set_type: Received an error when trying to set
95
+ # the transfer mode to binary or ASCII.
96
+ # * :partial_file: A file transfer was shorter or larger than
97
+ # expected. This happens when the server first reports an expected
98
+ # transfer size, and then delivers data that doesn't match the
99
+ # previously given size.
100
+ # * :ftp_couldnt_retr_file: This was either a weird reply to a
101
+ # 'RETR' command or a zero byte transfer complete.
102
+ # * :quote_error: When sending custom "QUOTE" commands to the
103
+ # remote server, one of the commands returned an error code that
104
+ # was 400 or higher (for FTP) or otherwise indicated unsuccessful
105
+ # completion of the command.
106
+ # * :http_returned_error: This is returned if CURLOPT_FAILONERROR is
107
+ # set TRUE and the HTTP server returns an error code that is >= 400.
108
+ # * :write_error: An error occurred when writing received data to a
109
+ # local file, or an error was returned to libcurl from a write callback.
110
+ # * :upload_failed: Failed starting the upload. For FTP, the server
111
+ # typically denied the STOR command. The error buffer usually
112
+ # contains the server's explanation for this.
113
+ # * :read_error: There was a problem reading a local file or an error
114
+ # returned by the read callback.
115
+ # * :out_of_memory: A memory allocation request failed. This is serious
116
+ # badness and things are severely screwed up if this ever occurs.
117
+ # * :operation_timedout: Operation timeout. The specified time-out
118
+ # period was reached according to the conditions.
119
+ # * :ftp_port_failed: The FTP PORT command returned error. This mostly
120
+ # happens when you haven't specified a good enough address for
121
+ # libcurl to use. See CURLOPT_FTPPORT.
122
+ # * :ftp_couldnt_use_rest: The FTP REST command returned error. This
123
+ # should never happen if the server is sane.
124
+ # * :range_error: The server does not support or accept range requests.
125
+ # * :http_post_error: This is an odd error that mainly occurs due to
126
+ # internal confusion.
127
+ # * :ssl_connect_error: A problem occurred somewhere in the SSL/TLS
128
+ # handshake. You really want the error buffer and read the message
129
+ # there as it pinpoints the problem slightly more. Could be
130
+ # certificates (file formats, paths, permissions), passwords, and others.
131
+ # * :bad_download_resume: The download could not be resumed because
132
+ # the specified offset was out of the file boundary.
133
+ # * :file_couldnt_read_file: A file given with FILE:// couldn't be
134
+ # opened. Most likely because the file path doesn't identify an
135
+ # existing file. Did you check file permissions?
136
+ # * :ldap_cannot_bind: LDAP cannot bind. LDAP bind operation failed.
137
+ # * :ldap_search_failed: LDAP search failed.
138
+ # * :function_not_found: Function not found. A required zlib function was not found.
139
+ # * :aborted_by_callback: Aborted by callback. A callback returned
140
+ # "abort" to libcurl.
141
+ # * :bad_function_argument: Internal error. A function was called with
142
+ # a bad parameter.
143
+ # * :interface_failed: Interface error. A specified outgoing interface
144
+ # could not be used. Set which interface to use for outgoing
145
+ # connections' source IP address with CURLOPT_INTERFACE.
146
+ # * :too_many_redirects: Too many redirects. When following redirects,
147
+ # libcurl hit the maximum amount. Set your limit with CURLOPT_MAXREDIRS.
148
+ # * :unknown_option: An option passed to libcurl is not recognized/known.
149
+ # Refer to the appropriate documentation. This is most likely a
150
+ # problem in the program that uses libcurl. The error buffer might
151
+ # contain more specific information about which exact option it concerns.
152
+ # * :telnet_option_syntax: A telnet option string was Illegally formatted.
153
+ # * :peer_failed_verification: The remote server's SSL certificate or
154
+ # SSH md5 fingerprint was deemed not OK.
155
+ # * :got_nothing: Nothing was returned from the server, and under the
156
+ # circumstances, getting nothing is considered an error.
157
+ # * :ssl_engine_notfound: The specified crypto engine wasn't found.
158
+ # * :ssl_engine_setfailed: Failed setting the selected SSL crypto engine as default!
159
+ # * :send_error: Failed sending network data.
160
+ # * :recv_error: Failure with receiving network data.
161
+ # * :ssl_certproblem: problem with the local client certificate.
162
+ # * :ssl_cipher: Couldn't use specified cipher.
163
+ # * :bad_content_encoding: Unrecognized transfer encoding.
164
+ # * :ldap_invalid_url: Invalid LDAP URL.
165
+ # * :filesize_exceeded: Maximum file size exceeded.
166
+ # * :use_ssl_failed: Requested FTP SSL level failed.
167
+ # * :send_fail_rewind: When doing a send operation curl had to rewind the data to
168
+ # retransmit, but the rewinding operation failed.
169
+ # * :ssl_engine_initfailed: Initiating the SSL Engine failed.
170
+ # * :login_denied: The remote server denied curl to login
171
+ # * :tftp_notfound: File not found on TFTP server.
172
+ # * :tftp_perm: Permission problem on TFTP server.
173
+ # * :remote_disk_full: Out of disk space on the server.
174
+ # * :tftp_illegal: Illegal TFTP operation.
175
+ # * :tftp_unknownid: Unknown TFTP transfer ID.
176
+ # * :remote_file_exists: File already exists and will not be overwritten.
177
+ # * :tftp_nosuchuser: This error should never be returned by a properly
178
+ # functioning TFTP server.
179
+ # * :conv_failed: Character conversion failed.
180
+ # * :conv_reqd: Caller must register conversion callbacks.
181
+ # * :ssl_cacert_badfile: Problem with reading the SSL CA cert (path? access rights?):
182
+ # * :remote_file_not_found: The resource referenced in the URL does not exist.
183
+ # * :ssh: An unspecified error occurred during the SSH session.
184
+ # * :ssl_shutdown_failed: Failed to shut down the SSL connection.
185
+ # * :again: Socket is not ready for send/recv wait till it's ready and try again.
186
+ # This return code is only returned from curl_easy_recv(3) and curl_easy_send(3)
187
+ # * :ssl_crl_badfile: Failed to load CRL file
188
+ # * :ssl_issuer_error: Issuer check failed
189
+ # * :ftp_pret_failed: The FTP server does not understand the PRET command at
190
+ # all or does not support the given argument. Be careful when
191
+ # using CURLOPT_CUSTOMREQUEST, a custom LIST command will be sent with PRET CMD
192
+ # before PASV as well.
193
+ # * :rtsp_cseq_error: Mismatch of RTSP CSeq numbers.
194
+ # * :rtsp_session_error: Mismatch of RTSP Session Identifiers.
195
+ # * :ftp_bad_file_list: Unable to parse FTP file list (during FTP wildcard downloading).
196
+ # * :chunk_failed: Chunk callback reported error.
197
+ # * :obsolete: These error codes will never be returned. They were used in an old
198
+ # libcurl version and are currently unused.
199
+ #
200
+ # @see http://curl.haxx.se/libcurl/c/libcurl-errors.html
201
+ attr_accessor :return_code
202
+
203
+ # Initialize a new Easy.
204
+ # It initializes curl, if not already done and applies the provided options.
205
+ # Look into {Ethon::Easy::Options Options} to see what you can provide in the
206
+ # options hash.
207
+ #
208
+ # @example Create a new Easy.
209
+ # Easy.new(url: "www.google.de")
210
+ #
211
+ # @param [ Hash ] options The options to set.
212
+ # @option options :headers [ Hash ] Request headers.
213
+ #
214
+ # @return [ Easy ] A new Easy.
215
+ #
216
+ # @see Ethon::Easy::Options
217
+ # @see http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
218
+ def initialize(options = {})
219
+ Curl.init
220
+ set_attributes(options)
221
+ set_callbacks
222
+ end
223
+
224
+ # Set given options.
225
+ #
226
+ # @example Set options.
227
+ # easy.set_attributes(options)
228
+ #
229
+ # @param [ Hash ] options The options.
230
+ #
231
+ # @raise InvalidOption
232
+ #
233
+ # @see initialize
234
+ def set_attributes(options)
235
+ options.each_pair do |key, value|
236
+ method = "#{key}="
237
+ unless respond_to?(method)
238
+ raise Errors::InvalidOption.new(key)
239
+ end
240
+ send(method, value)
241
+ end
242
+ end
243
+
244
+ # Reset easy. This means resetting all options and instance variables.
245
+ # Also the easy handle is resetted.
246
+ #
247
+ # @example Reset.
248
+ # easy.reset
249
+ def reset
250
+ @url = nil
251
+ @escape = nil
252
+ @hash = nil
253
+ @on_complete = nil
254
+ @on_headers = nil
255
+ @on_body = nil
256
+ @on_progress = nil
257
+ @procs = nil
258
+ @mirror = nil
259
+ Curl.easy_reset(handle)
260
+ set_callbacks
261
+ end
262
+
263
+ # Clones libcurl session handle. This means that all options that is set in
264
+ # the current handle will be set on duplicated handle.
265
+ def dup
266
+ e = super
267
+ e.handle = Curl.easy_duphandle(handle)
268
+ e.instance_variable_set(:@body_write_callback, nil)
269
+ e.instance_variable_set(:@header_write_callback, nil)
270
+ e.instance_variable_set(:@debug_callback, nil)
271
+ e.instance_variable_set(:@progress_callback, nil)
272
+ e.set_callbacks
273
+ e
274
+ end
275
+ # Url escapes the value.
276
+ #
277
+ # @example Url escape.
278
+ # easy.escape(value)
279
+ #
280
+ # @param [ String ] value The value to escape.
281
+ #
282
+ # @return [ String ] The escaped value.
283
+ #
284
+ # @api private
285
+ def escape(value)
286
+ string_pointer = Curl.easy_escape(handle, value, value.bytesize)
287
+ returned_string = string_pointer.read_string
288
+ Curl.free(string_pointer)
289
+ returned_string
290
+ end
291
+
292
+ # Returns the informations available through libcurl as
293
+ # a hash.
294
+ #
295
+ # @return [ Hash ] The informations hash.
296
+ def to_hash
297
+ Kernel.warn("Ethon: Easy#to_hash is deprecated and will be removed, please use #mirror.")
298
+ mirror.to_hash
299
+ end
300
+
301
+ def mirror
302
+ @mirror ||= Mirror.from_easy(self)
303
+ end
304
+
305
+ # Return pretty log out.
306
+ #
307
+ # @example Return log out.
308
+ # easy.log_inspect
309
+ #
310
+ # @return [ String ] The log out.
311
+ def log_inspect
312
+ "EASY #{mirror.log_informations.map{|k, v| "#{k}=#{v}"}.flatten.join(' ')}"
313
+ end
314
+ end
315
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+ module Ethon
3
+ module Errors
4
+
5
+ # Default Ethon error class for all custom errors.
6
+ class EthonError < StandardError
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+ module Ethon
3
+ module Errors
4
+
5
+ # Raises when global_init failed.
6
+ class GlobalInit < EthonError
7
+ def initialize
8
+ super("An error occured initializing curl.")
9
+ end
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+ module Ethon
3
+ module Errors
4
+
5
+ # Raises when option is invalid.
6
+ class InvalidOption < EthonError
7
+ def initialize(option)
8
+ super("The option: #{option} is invalid.")
9
+ end
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+ module Ethon
3
+ module Errors
4
+
5
+ # Raises when option is invalid.
6
+ class InvalidValue < EthonError
7
+ def initialize(option, value)
8
+ super("The value: #{value} is invalid for option: #{option}.")
9
+ end
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ module Ethon
3
+ module Errors
4
+
5
+ # Raises when multi_add_handle failed.
6
+ class MultiAdd < EthonError
7
+ def initialize(code, easy)
8
+ super("An error occured adding the easy handle: #{easy} to the multi: #{code}")
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ module Ethon
3
+ module Errors
4
+
5
+ # Raises when multi_fdset failed.
6
+ class MultiFdset < EthonError
7
+ def initialize(code)
8
+ super("An error occured getting the fdset: #{code}")
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ module Ethon
3
+ module Errors
4
+
5
+ # Raises when multi_remove_handle failed.
6
+ class MultiRemove < EthonError
7
+ def initialize(code, easy)
8
+ super("An error occured removing the easy handle: #{easy} from the multi: #{code}")
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+ module Ethon
3
+ module Errors
4
+
5
+ # Raised when multi_timeout failed.
6
+ class MultiTimeout < EthonError
7
+ def initialize(code)
8
+ super("An error occured getting the timeout: #{code}")
9
+ # "An error occured getting the timeout: #{code}: #{Curl.multi_strerror(code)}"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+ module Ethon
3
+ module Errors
4
+
5
+ # Raised when select failed.
6
+ class Select < EthonError
7
+ def initialize(errno)
8
+ super("An error occured on select: #{errno}")
9
+ end
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ require 'ethon/errors/ethon_error'
3
+ require 'ethon/errors/global_init'
4
+ require 'ethon/errors/multi_timeout'
5
+ require 'ethon/errors/multi_fdset'
6
+ require 'ethon/errors/multi_add'
7
+ require 'ethon/errors/multi_remove'
8
+ require 'ethon/errors/select'
9
+ require 'ethon/errors/invalid_option'
10
+ require 'ethon/errors/invalid_value'
11
+
12
+ module Ethon
13
+
14
+ # This namespace contains all errors raised by ethon.
15
+ module Errors
16
+ end
17
+ end
data/lib/ethon/libc.rb ADDED
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+ module Ethon
3
+
4
+ # FFI Wrapper module for Libc.
5
+ #
6
+ # @api private
7
+ module Libc
8
+ extend FFI::Library
9
+ ffi_lib 'c'
10
+
11
+ # :nodoc:
12
+ def self.windows?
13
+ Gem.win_platform?
14
+ end
15
+
16
+ unless windows?
17
+ attach_function :getdtablesize, [], :int
18
+ attach_function :free, [:pointer], :void
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,59 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ module Ethon
4
+
5
+ # Contains logging behaviour.
6
+ module Loggable
7
+
8
+ # Get the logger.
9
+ #
10
+ # @note Will try to grab Rails' logger first before creating a new logger
11
+ # with stdout.
12
+ #
13
+ # @example Get the logger.
14
+ # Loggable.logger
15
+ #
16
+ # @return [ Logger ] The logger.
17
+ def logger
18
+ return @logger if defined?(@logger)
19
+ @logger = rails_logger || default_logger
20
+ end
21
+
22
+ # Set the logger.
23
+ #
24
+ # @example Set the logger.
25
+ # Loggable.logger = Logger.new($stdout)
26
+ #
27
+ # @param [ Logger ] logger The logger to set.
28
+ #
29
+ # @return [ Logger ] The new logger.
30
+ def logger=(logger)
31
+ @logger = logger
32
+ end
33
+
34
+ private
35
+
36
+ # Gets the default Ethon logger - stdout.
37
+ #
38
+ # @example Get the default logger.
39
+ # Loggable.default_logger
40
+ #
41
+ # @return [ Logger ] The default logger.
42
+ def default_logger
43
+ logger = Logger.new($stdout)
44
+ logger.level = Logger::INFO
45
+ logger
46
+ end
47
+
48
+ # Get the Rails logger if it's defined.
49
+ #
50
+ # @example Get Rails' logger.
51
+ # Loggable.rails_logger
52
+ #
53
+ # @return [ Logger ] The Rails logger.
54
+ def rails_logger
55
+ defined?(::Rails) && ::Rails.respond_to?(:logger) && ::Rails.logger
56
+ end
57
+ end
58
+ extend Loggable
59
+ end