hanami-utils 0.7.2 → 0.8.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 +4 -4
- data/CHANGELOG.md +15 -2
- data/README.md +5 -1
- data/hanami-utils.gemspec +5 -6
- data/lib/hanami-utils.rb +1 -1
- data/lib/hanami/interactor.rb +7 -5
- data/lib/hanami/logger.rb +178 -30
- data/lib/hanami/utils/attributes.rb +11 -2
- data/lib/hanami/utils/basic_object.rb +4 -3
- data/lib/hanami/utils/blank.rb +45 -0
- data/lib/hanami/utils/callbacks.rb +1 -3
- data/lib/hanami/utils/class.rb +34 -3
- data/lib/hanami/utils/class_attribute.rb +5 -1
- data/lib/hanami/utils/deprecation.rb +2 -1
- data/lib/hanami/utils/duplicable.rb +2 -2
- data/lib/hanami/utils/escape.rb +53 -52
- data/lib/hanami/utils/hash.rb +9 -9
- data/lib/hanami/utils/inflector.rb +84 -62
- data/lib/hanami/utils/io.rb +2 -2
- data/lib/hanami/utils/json.rb +51 -0
- data/lib/hanami/utils/kernel.rb +12 -11
- data/lib/hanami/utils/load_paths.rb +4 -2
- data/lib/hanami/utils/path_prefix.rb +4 -3
- data/lib/hanami/utils/string.rb +12 -11
- data/lib/hanami/utils/version.rb +1 -1
- metadata +7 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e0ec07bde18ad072abdc5ba80712ccf9976d4139
|
4
|
+
data.tar.gz: 98916abdaf10d4a18848745fe00ba6b497a3e521
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 459b2bcf58fd4416d95421ed9d0af9995096caef9a32975a51ca69ebd771a8ba4352935f76f26702a1c248a7af256c01e0683101410800f02808761da548eaf7
|
7
|
+
data.tar.gz: 475a12099d5f21b95ccc7965571351e98f8b6eb55a46343952483eac7fdb3cb3f51daaa6818b99c5e991696caeda3a2bcb3910c078deb64e14a82e91f7612f0c
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,22 @@
|
|
1
1
|
# Hanami::Utils
|
2
2
|
Ruby core extentions and class utilities for Hanami
|
3
3
|
|
4
|
-
## v0.
|
4
|
+
## v0.8.0 - 2016-07-22
|
5
|
+
### Added
|
6
|
+
- [Andrey Morskov] Introduced `Hanami::Utils::Blank`
|
7
|
+
- [Anton Davydov] Allow to specify a default log level for `Hanami::Logger`
|
8
|
+
- [Anton Davydov] Introduced default and JSON formatters for `Hanami::Logger`
|
9
|
+
- [Erol Fornoles] Allow deep indifferent access for `Hanami::Utils::Attributes`
|
10
|
+
- [Anton Davydov] Introduced `Hanami::Utils::Json` which is a proxy for `MultiJson` (from `multi_json` gem), or fallback to `JSON` from Ruby standard library.
|
11
|
+
|
5
12
|
### Fixed
|
6
|
-
|
13
|
+
|
14
|
+
- [Hiếu Nguyễn] Ensure `Hanami::Utils::String#classify` to return already classified strings as they are. Eg. `"AwesomeProject"` should return `"AwesomeProject"`, not `"Awesomeproject"`.
|
15
|
+
- [TheSmartnik] Fix English pluralization for words ending with `"rses"`
|
16
|
+
- [Rogério Ramos] Fix English pluralization for words ending with `"ice"`
|
17
|
+
|
18
|
+
### Changed
|
19
|
+
- [Luca Guidi] Drop support for Ruby 2.0, 2.1 and Rubinius. Official support for JRuby 9.0.5.0+.
|
7
20
|
|
8
21
|
## v0.7.1 - 2016-02-05
|
9
22
|
### Fixed
|
data/README.md
CHANGED
@@ -22,7 +22,7 @@ Ruby core extentions and class utilities for [Hanami](http://hanamirb.org)
|
|
22
22
|
|
23
23
|
## Rubies
|
24
24
|
|
25
|
-
__Hanami::Utils__ supports Ruby (MRI) 2.2+, JRuby
|
25
|
+
__Hanami::Utils__ supports Ruby (MRI) 2.2+, JRuby 9.0.5.0+
|
26
26
|
|
27
27
|
## Installation
|
28
28
|
|
@@ -63,6 +63,10 @@ Set of attributes with indifferent access. [[API doc](http://www.rubydoc.info/ge
|
|
63
63
|
|
64
64
|
Enhanced version of Ruby's `BasicObject`. [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/BasicObject)]
|
65
65
|
|
66
|
+
### Hanami::Utils::Blank
|
67
|
+
|
68
|
+
Checks for blank. [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/Blank)]
|
69
|
+
|
66
70
|
### Hanami::Utils::Callbacks
|
67
71
|
|
68
72
|
Callbacks to decorate methods with `before` and `after` logic. It supports polymorphic callbacks (methods and procs). [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/Callbacks)]
|
data/hanami-utils.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Hanami::Utils::VERSION
|
9
9
|
spec.authors = ['Luca Guidi', 'Trung Lê', 'Alfonso Uceda']
|
10
10
|
spec.email = ['me@lucaguidi.com', 'trung.le@ruby-journal.com', 'uceda73@gmail.com']
|
11
|
-
spec.description =
|
12
|
-
spec.summary =
|
11
|
+
spec.description = 'Hanami utilities'
|
12
|
+
spec.summary = 'Ruby core extentions and Hanami utilities'
|
13
13
|
spec.homepage = 'http://hanamirb.org'
|
14
14
|
spec.license = 'MIT'
|
15
15
|
|
@@ -17,9 +17,8 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ['lib']
|
20
|
-
spec.required_ruby_version = '>= 2.
|
20
|
+
spec.required_ruby_version = '>= 2.2.0'
|
21
21
|
|
22
|
-
spec.add_development_dependency 'bundler',
|
23
|
-
spec.add_development_dependency 'rake',
|
24
|
-
spec.add_development_dependency 'minitest', '~> 5.4'
|
22
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
23
|
+
spec.add_development_dependency 'rake', '~> 11'
|
25
24
|
end
|
data/lib/hanami-utils.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require 'hanami/utils'
|
1
|
+
require 'hanami/utils' # rubocop:disable Style/FileName
|
data/lib/hanami/interactor.rb
CHANGED
@@ -17,7 +17,7 @@ module Hanami
|
|
17
17
|
# @api private
|
18
18
|
#
|
19
19
|
# @see Hanami::Interactor::Result#respond_to_missing?
|
20
|
-
METHODS =
|
20
|
+
METHODS = ::Hash[initialize: true, success?: true, fail!: true, prepare!: true, errors: true, error: true].freeze
|
21
21
|
|
22
22
|
# Initialize a new result
|
23
23
|
#
|
@@ -97,6 +97,7 @@ module Hanami
|
|
97
97
|
end
|
98
98
|
|
99
99
|
protected
|
100
|
+
|
100
101
|
# @since 0.3.5
|
101
102
|
# @api private
|
102
103
|
def method_missing(m, *)
|
@@ -105,7 +106,7 @@ module Hanami
|
|
105
106
|
|
106
107
|
# @since 0.3.5
|
107
108
|
# @api private
|
108
|
-
def respond_to_missing?(method_name,
|
109
|
+
def respond_to_missing?(method_name, _include_all)
|
109
110
|
method_name = method_name.to_sym
|
110
111
|
METHODS[method_name] || @payload.key?(method_name)
|
111
112
|
end
|
@@ -119,7 +120,7 @@ module Hanami
|
|
119
120
|
# @since 0.3.5
|
120
121
|
# @api private
|
121
122
|
def __inspect
|
122
|
-
" @success=#{
|
123
|
+
" @success=#{@success} @payload=#{@payload.inspect}"
|
123
124
|
end
|
124
125
|
end
|
125
126
|
|
@@ -251,6 +252,7 @@ module Hanami
|
|
251
252
|
end
|
252
253
|
|
253
254
|
private
|
255
|
+
|
254
256
|
# Check if proceed with <tt>#call</tt> invokation.
|
255
257
|
# By default it returns <tt>true</tt>.
|
256
258
|
#
|
@@ -459,7 +461,7 @@ module Hanami
|
|
459
461
|
end
|
460
462
|
end
|
461
463
|
|
462
|
-
# Expose local instance variables into the
|
464
|
+
# Expose local instance variables into the returning value of <tt>#call</tt>
|
463
465
|
#
|
464
466
|
# @param instance_variable_names [Symbol,Array<Symbol>] one or more instance
|
465
467
|
# variable names
|
@@ -490,7 +492,7 @@ module Hanami
|
|
490
492
|
# result.params # => NoMethodError
|
491
493
|
def expose(*instance_variable_names)
|
492
494
|
instance_variable_names.each do |name|
|
493
|
-
exposures[name] = "@#{
|
495
|
+
exposures[name] = "@#{name}"
|
494
496
|
end
|
495
497
|
end
|
496
498
|
end
|
data/lib/hanami/logger.rb
CHANGED
@@ -1,34 +1,51 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'json'
|
1
3
|
require 'logger'
|
2
4
|
require 'hanami/utils/string'
|
5
|
+
require 'hanami/utils/json'
|
6
|
+
require 'hanami/utils/class_attribute'
|
3
7
|
|
4
8
|
module Hanami
|
5
9
|
# Hanami logger
|
6
10
|
#
|
7
11
|
# Implement with the same interface of Ruby std lib `Logger`.
|
8
|
-
# It uses `STDOUT` as output
|
9
|
-
#
|
12
|
+
# It uses `STDOUT`, `STDERR`, file name or open file as output stream.
|
10
13
|
#
|
11
14
|
#
|
12
15
|
# When a Hanami application is initialized, it creates a logger for that specific application.
|
13
16
|
# For instance for a `Bookshelf::Application` a `Bookshelf::Logger` will be available.
|
14
17
|
#
|
15
|
-
# This is useful for auto-tagging the output. Eg (`
|
16
|
-
#
|
17
|
-
# When used stand alone (eg. `Hanami::Logger.info`), it tags lines with `[Shared]`.
|
18
|
+
# This is useful for auto-tagging the output. Eg (`app=Booshelf`).
|
18
19
|
#
|
20
|
+
# When used stand alone (eg. `Hanami::Logger.info`), it tags lines with `app=Shared`.
|
19
21
|
#
|
20
22
|
#
|
21
23
|
# The available severity levels are the same of `Logger`:
|
22
24
|
#
|
23
|
-
# *
|
24
|
-
# *
|
25
|
-
# *
|
26
|
-
# *
|
27
|
-
# *
|
28
|
-
# *
|
25
|
+
# * DEBUG
|
26
|
+
# * INFO
|
27
|
+
# * WARN
|
28
|
+
# * ERROR
|
29
|
+
# * FATAL
|
30
|
+
# * UNKNOWN
|
29
31
|
#
|
30
32
|
# Those levels are available both as class and instance methods.
|
31
33
|
#
|
34
|
+
# Also Hanami::Logger support different formatters. Now available only two:
|
35
|
+
#
|
36
|
+
# * Formatter (default)
|
37
|
+
# * JSONFormatter
|
38
|
+
#
|
39
|
+
# And if you want to use custom formatter you need create new class inherited from
|
40
|
+
# `Formatter` class and define `_format` private method like this:
|
41
|
+
#
|
42
|
+
# class CustomFormatter < Formatter
|
43
|
+
# private
|
44
|
+
# def _format(hash)
|
45
|
+
# # ...
|
46
|
+
# end
|
47
|
+
# end
|
48
|
+
#
|
32
49
|
# @since 0.5.0
|
33
50
|
#
|
34
51
|
# @see http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc/Logger.html
|
@@ -47,34 +64,75 @@ module Hanami
|
|
47
64
|
# # or
|
48
65
|
# Bookshelf::Application.new
|
49
66
|
#
|
50
|
-
# Bookshelf::Logger.info('Hello')
|
51
|
-
# # => I, [2015-01-10T21:55:12.727259 #80487] INFO -- [Bookshelf] : Hello
|
52
|
-
#
|
53
67
|
# Bookshelf::Logger.new.info('Hello')
|
54
|
-
# # =>
|
68
|
+
# # => app=Bookshelf severity=INFO time=1988-09-01 00:00:00 UTC message=Hello
|
55
69
|
#
|
56
70
|
# @example Standalone usage
|
57
|
-
# require 'hanami'
|
58
|
-
#
|
59
|
-
# Hanami::Logger.info('Hello')
|
60
|
-
# # => I, [2015-01-10T21:55:12.727259 #80487] INFO -- [Hanami] : Hello
|
71
|
+
# require 'hanami/logger'
|
61
72
|
#
|
62
73
|
# Hanami::Logger.new.info('Hello')
|
63
|
-
# # =>
|
74
|
+
# # => app=Hanami severity=INFO time=2016-05-27 10:14:42 UTC message=Hello
|
64
75
|
#
|
65
76
|
# @example Custom tagging
|
66
|
-
# require 'hanami'
|
77
|
+
# require 'hanami/logger'
|
67
78
|
#
|
68
79
|
# Hanami::Logger.new('FOO').info('Hello')
|
69
|
-
# # =>
|
80
|
+
# # => app=FOO severity=INFO time=2016-05-27 10:14:42 UTC message=Hello
|
81
|
+
#
|
82
|
+
# @example Write to file
|
83
|
+
# require 'hanami'
|
84
|
+
#
|
85
|
+
# Hanami::Logger.new(stream: 'logfile.log').info('Hello')
|
86
|
+
# # in logfile.log
|
87
|
+
# # => app=FOO severity=INFO time=2016-05-27 10:14:42 UTC message=Hello
|
88
|
+
#
|
89
|
+
# @example Use JSON formatter
|
90
|
+
# require 'hanami'
|
91
|
+
#
|
92
|
+
# Hanami::Logger.new(formatter: Hanami::Logger::JSONFormatter).info('Hello')
|
93
|
+
# # => "{\"app\":\"Hanami\",\"severity\":\"INFO\",\"time\":\"1988-09-01 00:00:00 UTC\",\"message\":\"Hello\"}"
|
70
94
|
class Logger < ::Logger
|
71
|
-
# Hanami::Logger default formatter
|
95
|
+
# Hanami::Logger default formatter.
|
96
|
+
# This formatter returns string in key=value format.
|
72
97
|
#
|
73
98
|
# @since 0.5.0
|
74
99
|
# @api private
|
75
100
|
#
|
76
101
|
# @see http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc/Logger/Formatter.html
|
77
102
|
class Formatter < ::Logger::Formatter
|
103
|
+
# @since 0.8.0
|
104
|
+
# @api private
|
105
|
+
SEPARATOR = ' '.freeze
|
106
|
+
|
107
|
+
# @since 0.8.0
|
108
|
+
# @api private
|
109
|
+
NEW_LINE = $/
|
110
|
+
|
111
|
+
include Utils::ClassAttribute
|
112
|
+
|
113
|
+
class_attribute :subclasses
|
114
|
+
self.subclasses = Set.new
|
115
|
+
|
116
|
+
def self.fabricate(formatter, application_name)
|
117
|
+
case formatter
|
118
|
+
when Symbol
|
119
|
+
(subclasses.find { |s| s.eligible?(formatter) } || self).new
|
120
|
+
when nil
|
121
|
+
new
|
122
|
+
else
|
123
|
+
formatter
|
124
|
+
end.tap { |f| f.application_name = application_name }
|
125
|
+
end
|
126
|
+
|
127
|
+
def self.inherited(subclass)
|
128
|
+
super
|
129
|
+
subclasses << subclass
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.eligible?(name)
|
133
|
+
name == :default
|
134
|
+
end
|
135
|
+
|
78
136
|
# @since 0.5.0
|
79
137
|
# @api private
|
80
138
|
attr_writer :application_name
|
@@ -83,9 +141,58 @@ module Hanami
|
|
83
141
|
# @api private
|
84
142
|
#
|
85
143
|
# @see http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc/Logger/Formatter.html#method-i-call
|
86
|
-
def call(severity, time,
|
87
|
-
|
88
|
-
|
144
|
+
def call(severity, time, _progname, msg)
|
145
|
+
_format({
|
146
|
+
app: @application_name,
|
147
|
+
severity: severity,
|
148
|
+
time: time.utc
|
149
|
+
}.merge(
|
150
|
+
_message_hash(msg)
|
151
|
+
))
|
152
|
+
end
|
153
|
+
|
154
|
+
private
|
155
|
+
|
156
|
+
# @since 0.8.0
|
157
|
+
# @api private
|
158
|
+
def _message_hash(message) # rubocop:disable Metrics/MethodLength
|
159
|
+
case message
|
160
|
+
when Hash
|
161
|
+
message
|
162
|
+
when Exception
|
163
|
+
Hash[
|
164
|
+
message: message.message,
|
165
|
+
backtrace: message.backtrace || [],
|
166
|
+
error: message.class
|
167
|
+
]
|
168
|
+
else
|
169
|
+
Hash[message: message]
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# @since 0.8.0
|
174
|
+
# @api private
|
175
|
+
def _format(hash)
|
176
|
+
hash.map { |k, v| "#{k}=#{v}" }.join(SEPARATOR) + NEW_LINE
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# Hanami::Logger JSON formatter.
|
181
|
+
# This formatter returns string in JSON format.
|
182
|
+
#
|
183
|
+
# @since 0.5.0
|
184
|
+
# @api private
|
185
|
+
class JSONFormatter < Formatter
|
186
|
+
def self.eligible?(name)
|
187
|
+
name == :json
|
188
|
+
end
|
189
|
+
|
190
|
+
private
|
191
|
+
|
192
|
+
# @since 0.8.0
|
193
|
+
# @api private
|
194
|
+
def _format(hash)
|
195
|
+
Hanami::Utils::Json.dump(hash)
|
89
196
|
end
|
90
197
|
end
|
91
198
|
|
@@ -96,6 +203,17 @@ module Hanami
|
|
96
203
|
# @api private
|
97
204
|
DEFAULT_APPLICATION_NAME = 'Hanami'.freeze
|
98
205
|
|
206
|
+
# @since 0.8.0
|
207
|
+
# @api private
|
208
|
+
LEVELS = Hash[
|
209
|
+
'debug' => DEBUG,
|
210
|
+
'info' => INFO,
|
211
|
+
'warn' => WARN,
|
212
|
+
'error' => ERROR,
|
213
|
+
'fatal' => FATAL,
|
214
|
+
'unknown' => UNKNOWN
|
215
|
+
].freeze
|
216
|
+
|
99
217
|
# @since 0.5.0
|
100
218
|
# @api private
|
101
219
|
attr_writer :application_name
|
@@ -105,12 +223,17 @@ module Hanami
|
|
105
223
|
# @param application_name [String] an optional application name used for
|
106
224
|
# tagging purposes
|
107
225
|
#
|
226
|
+
# @param stream [String, IO, StringIO, Pathname] an optional log stream. This is a filename
|
227
|
+
# (String) or IO object (typically STDOUT, STDERR, or an open file).
|
228
|
+
#
|
108
229
|
# @since 0.5.0
|
109
|
-
def initialize(application_name = nil)
|
110
|
-
super(
|
230
|
+
def initialize(application_name = nil, stream: STDOUT, level: DEBUG, formatter: nil)
|
231
|
+
super(stream)
|
111
232
|
|
233
|
+
@level = _level(level)
|
234
|
+
@stream = stream
|
112
235
|
@application_name = application_name
|
113
|
-
@formatter =
|
236
|
+
@formatter = Formatter.fabricate(formatter, self.application_name)
|
114
237
|
end
|
115
238
|
|
116
239
|
# Returns the current application name, this is used for tagging purposes
|
@@ -122,14 +245,28 @@ module Hanami
|
|
122
245
|
@application_name || _application_name_from_namespace || _default_application_name
|
123
246
|
end
|
124
247
|
|
248
|
+
# @since 0.8.0
|
249
|
+
# @api private
|
250
|
+
def level=(value)
|
251
|
+
super _level(value)
|
252
|
+
end
|
253
|
+
|
254
|
+
# Close the logging stream if this stream isn't an STDOUT
|
255
|
+
#
|
256
|
+
# @since 0.8.0
|
257
|
+
def close
|
258
|
+
super unless [STDOUT, $stdout].include?(@stream)
|
259
|
+
end
|
260
|
+
|
125
261
|
private
|
262
|
+
|
126
263
|
# @since 0.5.0
|
127
264
|
# @api private
|
128
265
|
def _application_name_from_namespace
|
129
266
|
class_name = self.class.name
|
130
267
|
namespace = Utils::String.new(class_name).namespace
|
131
268
|
|
132
|
-
class_name != namespace and return namespace
|
269
|
+
class_name != namespace and return namespace # rubocop:disable Style/AndOr
|
133
270
|
end
|
134
271
|
|
135
272
|
# @since 0.5.0
|
@@ -137,5 +274,16 @@ module Hanami
|
|
137
274
|
def _default_application_name
|
138
275
|
DEFAULT_APPLICATION_NAME
|
139
276
|
end
|
277
|
+
|
278
|
+
# @since 0.8.0
|
279
|
+
# @api private
|
280
|
+
def _level(level)
|
281
|
+
case level
|
282
|
+
when DEBUG..UNKNOWN
|
283
|
+
level
|
284
|
+
else
|
285
|
+
LEVELS.fetch(level.to_s.downcase, DEBUG)
|
286
|
+
end
|
287
|
+
end
|
140
288
|
end
|
141
289
|
end
|
@@ -66,11 +66,20 @@ module Hanami
|
|
66
66
|
# attributes[:unknown] # => nil
|
67
67
|
# attributes['unknown'] # => nil
|
68
68
|
def get(attribute)
|
69
|
-
@attributes
|
69
|
+
value = @attributes
|
70
|
+
|
71
|
+
keys = attribute.to_s.split('.')
|
72
|
+
keys.each do |key|
|
73
|
+
break unless value
|
74
|
+
|
75
|
+
value = value[key]
|
76
|
+
end
|
77
|
+
|
78
|
+
value.is_a?(Hash) ? self.class.new(value) : value
|
70
79
|
end
|
71
80
|
|
72
81
|
# @since 0.3.4
|
73
|
-
|
82
|
+
alias [] get
|
74
83
|
|
75
84
|
# Set the given value for the given attribute
|
76
85
|
#
|