hanami-utils 0.7.2 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
#
|