hanami-utils 0.0.0 → 0.7.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 +183 -0
- data/LICENSE.md +22 -0
- data/README.md +106 -7
- data/hanami-utils.gemspec +15 -13
- data/lib/hanami-utils.rb +1 -0
- data/lib/hanami/interactor.rb +497 -0
- data/lib/hanami/logger.rb +141 -0
- data/lib/hanami/utils.rb +31 -2
- data/lib/hanami/utils/attributes.rb +132 -0
- data/lib/hanami/utils/basic_object.rb +53 -0
- data/lib/hanami/utils/callbacks.rb +286 -0
- data/lib/hanami/utils/class.rb +94 -0
- data/lib/hanami/utils/class_attribute.rb +95 -0
- data/lib/hanami/utils/deprecation.rb +70 -0
- data/lib/hanami/utils/duplicable.rb +80 -0
- data/lib/hanami/utils/escape.rb +577 -0
- data/lib/hanami/utils/hash.rb +299 -0
- data/lib/hanami/utils/inflector.rb +439 -0
- data/lib/hanami/utils/io.rb +37 -0
- data/lib/hanami/utils/kernel.rb +1031 -0
- data/lib/hanami/utils/load_paths.rb +167 -0
- data/lib/hanami/utils/path_prefix.rb +146 -0
- data/lib/hanami/utils/string.rb +419 -0
- data/lib/hanami/utils/version.rb +4 -1
- metadata +51 -16
- data/.gitignore +0 -9
- data/Gemfile +0 -4
- data/Rakefile +0 -2
- data/bin/console +0 -14
- data/bin/setup +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d7bd99764bc258d92e6fdbb95ee0b703b80728e
|
4
|
+
data.tar.gz: 76e1e00e98a9ba63f6b6516099613f8628e7c676
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dbc1321581bee6c3e0400ad4596b7b712f817550b94536010a573153c0dd53d7fe0cc0201621cfd1502fa531e38a7b040fa314801f671f6bf3bd74521b12a248
|
7
|
+
data.tar.gz: ae7b724c1ae87c3b5c5ba5cde7740e3be157edf9e9c6773b2f97c4e75432090dd29dac4c846d7ca62f6b00e4bd5984e4f933315c0ce9aee9058d1222f9e1b641
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
# Hanami::Utils
|
2
|
+
Ruby core extentions and class utilities for Hanami
|
3
|
+
|
4
|
+
## v0.7.0 - 2016-01-22
|
5
|
+
### Changed
|
6
|
+
- [Luca Guidi] Renamed the project
|
7
|
+
|
8
|
+
## v0.6.1 - 2016-01-19
|
9
|
+
### Fixed
|
10
|
+
- [Anton Davydov] Ensure `Lotus::Utils::String#classify` to work properly with dashes (eg. `"app-store" => "App::Store"`)
|
11
|
+
|
12
|
+
## v0.6.0 - 2016-01-12
|
13
|
+
### Added
|
14
|
+
- [Luca Guidi] Official support for Ruby 2.3
|
15
|
+
- [Luca Guidi] Custom inflections
|
16
|
+
- [Luca Guidi] Introduced `Lotus::Utils::Duplicable` as a safe dup logic for Ruby types
|
17
|
+
- [Luca Guidi] Added `Lotus::Utils::String#rsub` replace rightmost occurrence
|
18
|
+
|
19
|
+
### Fixed
|
20
|
+
- [Luca Guidi] Fix `Lotus::Utils::PathPrefix#join` and `#relative_join` by rejecting arguments that are equal to the separator
|
21
|
+
- [Karim Kiatlottiavi] Fix `Encoding::UndefinedConversionError` in `Lotus::Utils::Escape.encode`
|
22
|
+
|
23
|
+
### Changed
|
24
|
+
- [Luca Guidi] Deprecate Ruby 2.0 and 2.1
|
25
|
+
- [Luca Guidi] Removed `Lotus::Utils::Callbacks#add` in favor of `#append`
|
26
|
+
- [Luca Guidi] Removed pattern support for `Utils::Class.load!` (eg. `Articles(Controller|::Controller)`)
|
27
|
+
|
28
|
+
## v0.5.2 - 2015-09-30
|
29
|
+
### Added
|
30
|
+
- [Luca Guidi] Added `Lotus::Utils::String#capitalize`
|
31
|
+
- [Trung Lê] Official support for JRuby 9k+
|
32
|
+
|
33
|
+
## v0.5.1 - 2015-07-10
|
34
|
+
### Fixed
|
35
|
+
- [Thiago Felippe] Ensure `Lotus::Utils::PathPrefix#join` won't remote duplicate entries (eg `/admin/dashboard/admin`)
|
36
|
+
|
37
|
+
## v0.5.0 - 2015-06-23
|
38
|
+
### Added
|
39
|
+
- [Luca Guidi] Extracted `Lotus::Logger` from `hanamirb`
|
40
|
+
|
41
|
+
### Changed
|
42
|
+
- [Luca Guidi] `Lotus::Interactor::Result` contains only objects explicitly exposed via `Lotus::Interactor.expose`.
|
43
|
+
|
44
|
+
## v0.4.3 - 2015-05-22
|
45
|
+
### Added
|
46
|
+
- [François Beausoleil] Improved `Lotus::Utils::Kernel` messages for `TypeError`.
|
47
|
+
|
48
|
+
## v0.4.2 - 2015-05-15
|
49
|
+
### Fixed
|
50
|
+
- [Luca Guidi] Ensure `Lotus::Utils::Attributes#to_h` to return `::Hash`
|
51
|
+
|
52
|
+
## v0.4.1 - 2015-05-15
|
53
|
+
### Added
|
54
|
+
- [Luca Guidi & Alfonso Uceda Pompa] Introduced `Lotus::Utils::Inflector`, `Lotus::Utils::String#pluralize` and `#singularize`
|
55
|
+
|
56
|
+
### Fixed
|
57
|
+
- [Luca Guidi] Ensure `Lotus::Utils::Attributes#to_h` to safely return nested `::Hash` instances for complex data structures.
|
58
|
+
- [Luca Guidi] Let `Lotus::Interactor#error` to return a falsey value for control flow. (eg. `check_permissions or error "You can't access"`)
|
59
|
+
|
60
|
+
## v0.4.0 - 2015-03-23
|
61
|
+
### Added
|
62
|
+
- [Luca Guidi] Introduced `Lotus::Utils::Escape`. It implements OWASP/ESAPI suggestions for HTML, HTML attribute and URL escape utilities.
|
63
|
+
- [Luca Guidi] Introduced `Lotus::Utils::String#dasherize`
|
64
|
+
- [Luca Guidi] Introduced `Lotus::Utils::String#titleize`
|
65
|
+
|
66
|
+
## v0.3.5 - 2015-03-12
|
67
|
+
### Added
|
68
|
+
- [Luca Guidi] Introduced `Lotus::Interactor`
|
69
|
+
- [Luca Guidi] Introduced `Lotus::Utils::BasicObject`
|
70
|
+
|
71
|
+
## v0.3.4 - 2015-01-30
|
72
|
+
### Added
|
73
|
+
- [Alfonso Uceda Pompa] Aliased `Lotus::Utils::Attributes#get` with `#[]`
|
74
|
+
- [Simone Carletti] Introduced `Lotus::Utils::Callbacks::Chain#prepend` and `#append`
|
75
|
+
|
76
|
+
### Deprecated
|
77
|
+
- [Luca Guidi] Deprecated `Lotus::Utils::Callbacks::Chain#add` in favor of `#append`
|
78
|
+
|
79
|
+
## v0.3.3 - 2015-01-08
|
80
|
+
### Fixed
|
81
|
+
- [Luca Guidi] Ensure to return the right offending object if a missing method is called with Utils::String and Hash (eg. `Utils::Hash.new(a: 1).all? {|_, v| v.foo }` blame `v` instead of `Hash`)
|
82
|
+
- [Luca Guidi] Raise an error if try to coerce non numeric strings into Integer, Float & BigDecimal (eg. `Utils::Kernel.Integer("hello") # => raise TypeError`)
|
83
|
+
|
84
|
+
## v0.3.2 - 2014-12-23
|
85
|
+
### Added
|
86
|
+
- [Luca Guidi] Official support for Ruby 2.2
|
87
|
+
- [Luca Guidi] Introduced `Utils::Attributes`
|
88
|
+
- [Luca Guidi] Added `Utils::Hash#stringify!`
|
89
|
+
|
90
|
+
## v0.3.1 - 2014-11-23
|
91
|
+
### Added
|
92
|
+
- [Luca Guidi] Allow `Utils::Class.load!` to accept any object that implements `#to_s`
|
93
|
+
- [Trung Lê] Allow `Utils::Class.load!` to accept a class
|
94
|
+
- [Luca Guidi] Introduced `Utils::Class.load_from_pattern!`
|
95
|
+
- [Luca Guidi] Introduced `Utils.jruby?` and `Utils.rubinius?`
|
96
|
+
- [Luca Guidi] Introduced `Utils::Deprecation`
|
97
|
+
- [Luca Guidi] Official support for Rubinius 2.3+
|
98
|
+
- [Luca Guidi] Official support for JRuby 1.7+ (with 2.0 mode)
|
99
|
+
- [Janko Marohnić] Implemented `Utils::PathPrefix` relativness and absolutness
|
100
|
+
- [Luca Guidi] Made `Utils::PathPrefix` `#join` and `#relative_join` to return a new instance of that class
|
101
|
+
- [Luca Guidi] Implemented `Utils::Hash#deep_dup`
|
102
|
+
- [Luca Guidi] Made `Utils::PathPrefix#join` to accept multiple argument
|
103
|
+
|
104
|
+
### Fixed
|
105
|
+
- [Luca Guidi] Made `Utils::PathPrefix#join` remove trailing occurrences for `@separator` from the output
|
106
|
+
- [Luca Guidi] Made `Utils::PathPrefix#relative_join` to correctly replace all the instances of `@separator` from the output
|
107
|
+
|
108
|
+
### Deprecated
|
109
|
+
- [Luca Guidi] Deprecated `Utils::Class.load!` with a pattern like `Articles(Controller|::Controller)`, use `Utils::Class.load_from_pattern!` instead
|
110
|
+
|
111
|
+
## v0.3.0 - 2014-10-23
|
112
|
+
### Added
|
113
|
+
- [Celso Fernandes] Add BigDecimal coercion to Lotus::Utils::Kernel
|
114
|
+
- [Luca Guidi] Define `Boolean` constant, if missing
|
115
|
+
- [Luca Guidi] Use composition over inheritance for `Lotus::Utils::PathPrefix`
|
116
|
+
- [Luca Guidi] Use composition over inheritance for `Lotus::Utils::Hash`
|
117
|
+
- [Luca Guidi] Use composition over inheritance for `Lotus::Utils::String`
|
118
|
+
|
119
|
+
### Fixed
|
120
|
+
- [Luca Guidi] Improved error message for `Utils::Class.load!`
|
121
|
+
- [Tom Kadwill] Improved error `NameError` message by passing in the whole constant name to `Utils::Class.load!`
|
122
|
+
- [Luca Guidi] `Utils::Hash#to_h` return instances of `::Hash` in case of nested symbolized data structure
|
123
|
+
- [Luca Guidi] Raise `TypeError` if `nil` is passed to `PathPrefix#relative_join`
|
124
|
+
- [Peter Suschlik] Define `Lotus::Utils::Hash#respond_to_missing?`
|
125
|
+
- [Peter Suschlik] Define `Lotus::Utils::String#responds_to_missing?`
|
126
|
+
- [Luca Guidi] Ensure `Utils::Hash#inspect` output to be the same of `::Hash#inspect`
|
127
|
+
|
128
|
+
## v0.2.0 - 2014-06-23
|
129
|
+
### Added
|
130
|
+
- [Luca Guidi] Implemented `Lotus::Utils::Kernel.Symbol`
|
131
|
+
- [Luca Guidi] Made `Kernel.Pathname` to raise an error when `nil` is passed as argument
|
132
|
+
- [Luca Guidi] Implemented `Lotus::Utils::LoadPaths#freeze` in order to prevent modification after the object has been frozen
|
133
|
+
- [Luca Guidi] Implemented Lotus::Utils::LoadPaths#push, also aliased as #<<
|
134
|
+
- [Luca Guidi] Use composition over inheritance for `Lotus::Utils::LoadPaths`
|
135
|
+
- [Luca Guidi] Introduced `Lotus::Utils::LoadPaths`
|
136
|
+
- [Luca Guidi] Introduced `Lotus::Utils::String#namespace`, in order to return the top level Ruby namespace for the given string
|
137
|
+
- [Luca Guidi] Implemented `Lotus::Utils::Kernel.Pathname`
|
138
|
+
|
139
|
+
### Fixed
|
140
|
+
- [Luca Guidi] Implemented `Lotus::Utils::LoadPaths#initialize_copy` in order to safely `#dup` and `#clone`
|
141
|
+
|
142
|
+
### Changed
|
143
|
+
- [Luca Guidi] Implemented `Lotus::Utils::Callbacks::Chain#freeze` in order to prevent modification after the object has been frozen
|
144
|
+
- [Luca Guidi] All the `Utils::Kernel` methods will raise `TypeError` in case of failed coercion.
|
145
|
+
- [Luca Guidi] Made `Kernel.Time` to raise an error when `nil` is passed as argument
|
146
|
+
- [Luca Guidi] Made `Kernel.DateTime` to raise an error when `nil` is passed as argument
|
147
|
+
- [Luca Guidi] Made `Kernel.Date` to raise an error when `nil` is passed as argument
|
148
|
+
- [Luca Guidi] Made `Kernel.Boolean` to return false when `nil` is passed as argument
|
149
|
+
- [Luca Guidi] Made `Kernel.String` to return an empty string when `nil` is passed as argument
|
150
|
+
- [Luca Guidi] Made `Kernel.Float` to return `0.0` when `nil` is passed as argument
|
151
|
+
- [Luca Guidi] Made `Kernel.Integer` to return `0` when `nil` is passed as argument
|
152
|
+
- [Luca Guidi] Made `Kernel.Hash` to return an empty `Hash` when `nil` is passed as argument
|
153
|
+
- [Luca Guidi] Made `Kernel.Set` to return an empty `Set` when `nil` is passed as argument
|
154
|
+
- [Luca Guidi] Made `Kernel.Array` to return an empty `Array` when `nil` is passed as argument
|
155
|
+
- [Luca Guidi] Use composition over inheritance for `Lotus::Utils::Callbacks::Chain`
|
156
|
+
|
157
|
+
## v0.1.1 - 2014-04-23
|
158
|
+
### Added
|
159
|
+
- [Luca Guidi] Implemented `Lotus::Utils::Kernel.Time`
|
160
|
+
- [Luca Guidi] Implemented `Lotus::Utils::Kernel.DateTime`
|
161
|
+
- [Luca Guidi] Implemented `Lotus::Utils::Kernel.Date`
|
162
|
+
- [Luca Guidi] Implemented `Lotus::Utils::Kernel.Float`
|
163
|
+
- [Luca Guidi] Implemented `Lotus::Utils::Kernel.Boolean`
|
164
|
+
- [Luca Guidi] Implemented `Lotus::Utils::Kernel.Hash`
|
165
|
+
- [Luca Guidi] Implemented `Lotus::Utils::Kernel.Set`
|
166
|
+
- [Luca Guidi] Implemented `Lotus::Utils::Kernel.String`
|
167
|
+
- [Luca Guidi] Implemented `Lotus::Utils::Kernel.Integer`
|
168
|
+
- [Luca Guidi] Implemented `Lotus::Utils::Kernel.Array`
|
169
|
+
|
170
|
+
### Fixed
|
171
|
+
- [Christopher Keele] Add missing stdlib `Set` require to `Utils::ClassAttribute`
|
172
|
+
|
173
|
+
## v0.1.0 - 2014-01-23
|
174
|
+
### Added
|
175
|
+
- [Luca Guidi] Introduced `Lotus::Utils::String#demodulize`
|
176
|
+
- [Luca Guidi] Introduced `Lotus::Utils::IO.silence_warnings`
|
177
|
+
- [Luca Guidi] Introduced class loading mechanism from a string: `Utils::Class.load!`
|
178
|
+
- [Luca Guidi] Introduced callbacks support for classes
|
179
|
+
- [Luca Guidi] Introduced inheritable class level attributes
|
180
|
+
- [Luca Guidi] Introduced `Utils::Hash`
|
181
|
+
- [Luca Guidi] Introduced `Utils::String`
|
182
|
+
- [Luca Guidi] Introduced `Utils::PathPrefix`
|
183
|
+
- [Luca Guidi] Official support for MRI 2.0+
|
data/LICENSE.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright © 2014-2016 Luca Guidi
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,8 +1,28 @@
|
|
1
1
|
# Hanami::Utils
|
2
2
|
|
3
|
-
|
3
|
+
Ruby core extentions and class utilities for [Hanami](http://hanamirb.org)
|
4
4
|
|
5
|
-
|
5
|
+
## Status
|
6
|
+
|
7
|
+
[](https://badge.fury.io/rb/hanami-utils)
|
8
|
+
[](https://travis-ci.org/hanami/utils?branch=master)
|
9
|
+
[](https://coveralls.io/r/hanami/utils)
|
10
|
+
[](https://codeclimate.com/github/hanami/utils)
|
11
|
+
[](https://gemnasium.com/hanami/utils)
|
12
|
+
[](http://inch-ci.org/github/hanami/utils)
|
13
|
+
|
14
|
+
## Contact
|
15
|
+
|
16
|
+
* Home page: http://hanamirb.org
|
17
|
+
* Mailing List: http://hanamirb.org/mailing-list
|
18
|
+
* API Doc: http://rdoc.info/gems/hanami-utils
|
19
|
+
* Bugs/Issues: https://github.com/hanami/utils/issues
|
20
|
+
* Support: http://stackoverflow.com/questions/tagged/hanami
|
21
|
+
* Chat: http://chat.hanamirb.org
|
22
|
+
|
23
|
+
## Rubies
|
24
|
+
|
25
|
+
__Hanami::Utils__ supports Ruby (MRI) 2.2+, JRuby 9k+
|
6
26
|
|
7
27
|
## Installation
|
8
28
|
|
@@ -22,15 +42,94 @@ Or install it yourself as:
|
|
22
42
|
|
23
43
|
## Usage
|
24
44
|
|
25
|
-
|
45
|
+
__Hanami::Utils__ is designed to enhance Ruby's code and stdlib.
|
46
|
+
**By default this gem doesn't load any code, you must require what you need.**
|
47
|
+
|
48
|
+
## Features
|
49
|
+
|
50
|
+
### Hanami::Interactor
|
51
|
+
|
52
|
+
Standardized Service Object with small interface and rich returning result. [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Interactor)]
|
53
|
+
|
54
|
+
### Hanami::Logger
|
55
|
+
|
56
|
+
Enhanced version of Ruby's `Logger`. [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Logger)]
|
57
|
+
|
58
|
+
### Hanami::Utils::Attributes
|
59
|
+
|
60
|
+
Set of attributes with indifferent access. [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/Attributes)]
|
61
|
+
|
62
|
+
### Hanami::Utils::BasicObject
|
63
|
+
|
64
|
+
Enhanced version of Ruby's `BasicObject`. [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/BasicObject)]
|
65
|
+
|
66
|
+
### Hanami::Utils::Callbacks
|
67
|
+
|
68
|
+
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)]
|
69
|
+
|
70
|
+
### Hanami::Utils::Class
|
71
|
+
|
72
|
+
Load classes from strings. It also supports namespaces. [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/Class)]
|
73
|
+
|
74
|
+
### Hanami::Utils::ClassAttribute
|
75
|
+
|
76
|
+
Inheritable class attributes. [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/ClassAttribute)]
|
77
|
+
|
78
|
+
### Hanami::Utils::Deprecation
|
26
79
|
|
27
|
-
|
80
|
+
Deprecate Hanami features. [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/Deprecation)]
|
28
81
|
|
29
|
-
|
82
|
+
### Hanami::Utils::Duplicable
|
30
83
|
|
31
|
-
|
84
|
+
Safe `#dup` logic for Ruby objects. [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/Deprecation)]
|
85
|
+
|
86
|
+
|
87
|
+
### Hanami::Utils::Escape
|
88
|
+
|
89
|
+
Safe and fast escape for URLs, HTML content and attributes. Based on OWASP/ESAPI code. [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/Escape)]
|
90
|
+
|
91
|
+
### Hanami::Utils::Hash
|
92
|
+
|
93
|
+
Enhanced version of Ruby's `Hash`. [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/Hash)]
|
94
|
+
|
95
|
+
### Hanami::Utils::IO
|
96
|
+
|
97
|
+
Silence Ruby warnings. [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/IO)]
|
98
|
+
|
99
|
+
### Hanami::Utils::Inflector
|
100
|
+
|
101
|
+
Complete and customizable english inflections (pluralization and singularization). [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/Inflector)]
|
102
|
+
|
103
|
+
### Hanami::Utils::Kernel
|
104
|
+
|
105
|
+
Type coercions for most common Ruby types. [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/Kernel)]
|
106
|
+
|
107
|
+
### Hanami::Utils::LoadPaths
|
108
|
+
|
109
|
+
Manage directories where to find Ruby source code or web static assets. [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/LoadPaths)]
|
110
|
+
|
111
|
+
### Hanami::Utils::PathPrefix
|
112
|
+
|
113
|
+
Safe logic to manage relative URLs. [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/PathPrefix)]
|
114
|
+
|
115
|
+
### Hanami::Utils::String
|
116
|
+
|
117
|
+
Enhanced version of Ruby's `String`. [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/String)]
|
118
|
+
|
119
|
+
## Versioning
|
120
|
+
|
121
|
+
__Hanami::Utils__ uses [Semantic Versioning 2.0.0](http://semver.org)
|
32
122
|
|
33
123
|
## Contributing
|
34
124
|
|
35
|
-
|
125
|
+
1. Fork it ( https://github.com/hanami/utils/fork )
|
126
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
127
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
128
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
129
|
+
5. Create new Pull Request
|
130
|
+
|
131
|
+
## Copyright
|
132
|
+
|
133
|
+
Copyright © 2014-2016 Luca Guidi – Released under MIT License
|
36
134
|
|
135
|
+
This project was formerly known as Lotus (`lotus-utils`).
|
data/hanami-utils.gemspec
CHANGED
@@ -4,20 +4,22 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'hanami/utils/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = 'hanami-utils'
|
8
8
|
spec.version = Hanami::Utils::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
9
|
+
spec.authors = ['Luca Guidi', 'Trung Lê', 'Alfonso Uceda']
|
10
|
+
spec.email = ['me@lucaguidi.com', 'trung.le@ruby-journal.com', 'uceda73@gmail.com']
|
11
|
+
spec.description = %q{Hanami utilities}
|
12
|
+
spec.summary = %q{Ruby core extentions and Hanami utilities}
|
13
|
+
spec.homepage = 'http://hanamirb.org'
|
14
|
+
spec.license = 'MIT'
|
11
15
|
|
12
|
-
spec.
|
13
|
-
spec.
|
14
|
-
spec.
|
16
|
+
spec.files = `git ls-files -- lib/* CHANGELOG.md LICENSE.md README.md hanami-utils.gemspec`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
spec.required_ruby_version = '>= 2.0.0'
|
15
21
|
|
16
|
-
spec.
|
17
|
-
spec.
|
18
|
-
spec.
|
19
|
-
spec.require_paths = ["lib"]
|
20
|
-
|
21
|
-
spec.add_development_dependency "bundler", "~> 1.11"
|
22
|
-
spec.add_development_dependency "rake", "~> 10.0"
|
22
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
23
|
+
spec.add_development_dependency 'rake', '~> 10'
|
24
|
+
spec.add_development_dependency 'minitest', '~> 5.4'
|
23
25
|
end
|
data/lib/hanami-utils.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'hanami/utils'
|
@@ -0,0 +1,497 @@
|
|
1
|
+
require 'hanami/utils/basic_object'
|
2
|
+
require 'hanami/utils/class_attribute'
|
3
|
+
require 'hanami/utils/hash'
|
4
|
+
|
5
|
+
module Hanami
|
6
|
+
# Hanami Interactor
|
7
|
+
#
|
8
|
+
# @since 0.3.5
|
9
|
+
module Interactor
|
10
|
+
# Result of an operation
|
11
|
+
#
|
12
|
+
# @since 0.3.5
|
13
|
+
class Result < Utils::BasicObject
|
14
|
+
# Concrete methods
|
15
|
+
#
|
16
|
+
# @since 0.3.5
|
17
|
+
# @api private
|
18
|
+
#
|
19
|
+
# @see Hanami::Interactor::Result#respond_to_missing?
|
20
|
+
METHODS = {initialize: true, success?: true, fail!: true, prepare!: true, errors: true, error: true}.freeze
|
21
|
+
|
22
|
+
# Initialize a new result
|
23
|
+
#
|
24
|
+
# @param payload [Hash] a payload to carry on
|
25
|
+
#
|
26
|
+
# @return [Hanami::Interactor::Result]
|
27
|
+
#
|
28
|
+
# @since 0.3.5
|
29
|
+
# @api private
|
30
|
+
def initialize(payload = {})
|
31
|
+
@payload = _payload(payload)
|
32
|
+
@errors = []
|
33
|
+
@success = true
|
34
|
+
end
|
35
|
+
|
36
|
+
# Check if the current status is successful
|
37
|
+
#
|
38
|
+
# @return [TrueClass,FalseClass] the result of the check
|
39
|
+
#
|
40
|
+
# @since 0.3.5
|
41
|
+
def success?
|
42
|
+
@success && errors.empty?
|
43
|
+
end
|
44
|
+
|
45
|
+
# Force the status to be a failure
|
46
|
+
#
|
47
|
+
# @since 0.3.5
|
48
|
+
def fail!
|
49
|
+
@success = false
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns all the errors collected during an operation
|
53
|
+
#
|
54
|
+
# @return [Array] the errors
|
55
|
+
#
|
56
|
+
# @since 0.3.5
|
57
|
+
#
|
58
|
+
# @see Hanami::Interactor::Result#error
|
59
|
+
# @see Hanami::Interactor#call
|
60
|
+
# @see Hanami::Interactor#error
|
61
|
+
# @see Hanami::Interactor#error!
|
62
|
+
def errors
|
63
|
+
@errors.dup
|
64
|
+
end
|
65
|
+
|
66
|
+
# @since 0.5.0
|
67
|
+
# @api private
|
68
|
+
def add_error(*errors)
|
69
|
+
@errors << errors
|
70
|
+
@errors.flatten!
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
|
74
|
+
# Returns the first errors collected during an operation
|
75
|
+
#
|
76
|
+
# @return [nil,String] the error, if present
|
77
|
+
#
|
78
|
+
# @since 0.3.5
|
79
|
+
#
|
80
|
+
# @see Hanami::Interactor::Result#errors
|
81
|
+
# @see Hanami::Interactor#call
|
82
|
+
# @see Hanami::Interactor#error
|
83
|
+
# @see Hanami::Interactor#error!
|
84
|
+
def error
|
85
|
+
errors.first
|
86
|
+
end
|
87
|
+
|
88
|
+
# Prepare the result before to be returned
|
89
|
+
#
|
90
|
+
# @param payload [Hash] an updated payload
|
91
|
+
#
|
92
|
+
# @since 0.3.5
|
93
|
+
# @api private
|
94
|
+
def prepare!(payload)
|
95
|
+
@payload.merge!(_payload(payload))
|
96
|
+
self
|
97
|
+
end
|
98
|
+
|
99
|
+
protected
|
100
|
+
# @since 0.3.5
|
101
|
+
# @api private
|
102
|
+
def method_missing(m, *)
|
103
|
+
@payload.fetch(m) { super }
|
104
|
+
end
|
105
|
+
|
106
|
+
# @since 0.3.5
|
107
|
+
# @api private
|
108
|
+
def respond_to_missing?(method_name, include_all)
|
109
|
+
method_name = method_name.to_sym
|
110
|
+
METHODS[method_name] || @payload.key?(method_name)
|
111
|
+
end
|
112
|
+
|
113
|
+
# @since 0.3.5
|
114
|
+
# @api private
|
115
|
+
def _payload(payload)
|
116
|
+
Utils::Hash.new(payload).symbolize!
|
117
|
+
end
|
118
|
+
|
119
|
+
# @since 0.3.5
|
120
|
+
# @api private
|
121
|
+
def __inspect
|
122
|
+
" @success=#{ @success } @payload=#{ @payload.inspect }"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Override for <tt>Module#included</tt>.
|
127
|
+
#
|
128
|
+
# @since 0.3.5
|
129
|
+
# @api private
|
130
|
+
def self.included(base)
|
131
|
+
super
|
132
|
+
|
133
|
+
base.class_eval do
|
134
|
+
prepend Interface
|
135
|
+
extend ClassMethods
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Interactor interface
|
140
|
+
#
|
141
|
+
# @since 0.3.5
|
142
|
+
module Interface
|
143
|
+
# Initialize an interactor
|
144
|
+
#
|
145
|
+
# It accepts arbitrary number of arguments.
|
146
|
+
# Developers can override it.
|
147
|
+
#
|
148
|
+
# @param args [Array<Object>] arbitrary number of arguments
|
149
|
+
#
|
150
|
+
# @return [Hanami::Interactor] the interactor
|
151
|
+
#
|
152
|
+
# @since 0.3.5
|
153
|
+
#
|
154
|
+
# @example Override #initialize
|
155
|
+
# require 'hanami/interactor'
|
156
|
+
#
|
157
|
+
# class UpdateProfile
|
158
|
+
# include Hanami::Interactor
|
159
|
+
#
|
160
|
+
# def initialize(user, params)
|
161
|
+
# @user = user
|
162
|
+
# @params = params
|
163
|
+
# end
|
164
|
+
#
|
165
|
+
# def call
|
166
|
+
# # ...
|
167
|
+
# end
|
168
|
+
# end
|
169
|
+
def initialize(*args)
|
170
|
+
super
|
171
|
+
ensure
|
172
|
+
@__result = ::Hanami::Interactor::Result.new
|
173
|
+
end
|
174
|
+
|
175
|
+
# Triggers the operation and return a result.
|
176
|
+
#
|
177
|
+
# All the instance variables will be available in the result.
|
178
|
+
#
|
179
|
+
# ATTENTION: This must be implemented by the including class.
|
180
|
+
#
|
181
|
+
# @return [Hanami::Interactor::Result] the result of the operation
|
182
|
+
#
|
183
|
+
# @raise [NoMethodError] if this isn't implemented by the including class.
|
184
|
+
#
|
185
|
+
# @example Expose instance variables in result payload
|
186
|
+
# require 'hanami/interactor'
|
187
|
+
#
|
188
|
+
# class Signup
|
189
|
+
# include Hanami::Interactor
|
190
|
+
# expose :user, :params
|
191
|
+
#
|
192
|
+
# def initialize(params)
|
193
|
+
# @params = params
|
194
|
+
# @user = User.new(@params)
|
195
|
+
# @foo = 'bar'
|
196
|
+
# end
|
197
|
+
#
|
198
|
+
# def call
|
199
|
+
# @user = UserRepository.persist(@user)
|
200
|
+
# end
|
201
|
+
# end
|
202
|
+
#
|
203
|
+
# result = Signup.new(name: 'Luca').call
|
204
|
+
# result.success? # => true
|
205
|
+
#
|
206
|
+
# result.user # => #<User:0x007fa311105778 @id=1 @name="Luca">
|
207
|
+
# result.params # => { :name=>"Luca" }
|
208
|
+
# result.foo # => raises NoMethodError
|
209
|
+
#
|
210
|
+
# @example Failed precondition
|
211
|
+
# require 'hanami/interactor'
|
212
|
+
#
|
213
|
+
# class Signup
|
214
|
+
# include Hanami::Interactor
|
215
|
+
# expose :user
|
216
|
+
#
|
217
|
+
# def initialize(params)
|
218
|
+
# @params = params
|
219
|
+
# @user = User.new(@params)
|
220
|
+
# end
|
221
|
+
#
|
222
|
+
# # THIS WON'T BE INVOKED BECAUSE #valid? WILL RETURN false
|
223
|
+
# def call
|
224
|
+
# @user = UserRepository.persist(@user)
|
225
|
+
# end
|
226
|
+
#
|
227
|
+
# private
|
228
|
+
# def valid?
|
229
|
+
# @params.valid?
|
230
|
+
# end
|
231
|
+
# end
|
232
|
+
#
|
233
|
+
# result = Signup.new(name: nil).call
|
234
|
+
# result.success? # => false
|
235
|
+
#
|
236
|
+
# result.user # => #<User:0x007fa311105778 @id=nil @name="Luca">
|
237
|
+
#
|
238
|
+
# @example Bad usage
|
239
|
+
# require 'hanami/interactor'
|
240
|
+
#
|
241
|
+
# class Signup
|
242
|
+
# include Hanami::Interactor
|
243
|
+
#
|
244
|
+
# # Method #call is not defined
|
245
|
+
# end
|
246
|
+
#
|
247
|
+
# Signup.new.call # => NoMethodError
|
248
|
+
def call
|
249
|
+
_call { super }
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
private
|
254
|
+
# Check if proceed with <tt>#call</tt> invokation.
|
255
|
+
# By default it returns <tt>true</tt>.
|
256
|
+
#
|
257
|
+
# Developers can override it.
|
258
|
+
#
|
259
|
+
# @return [TrueClass,FalseClass] the result of the check
|
260
|
+
#
|
261
|
+
# @since 0.3.5
|
262
|
+
def valid?
|
263
|
+
true
|
264
|
+
end
|
265
|
+
|
266
|
+
# Fail and interrupt the current flow.
|
267
|
+
#
|
268
|
+
# @since 0.3.5
|
269
|
+
#
|
270
|
+
# @example
|
271
|
+
# require 'hanami/interactor'
|
272
|
+
#
|
273
|
+
# class CreateEmailTest
|
274
|
+
# include Hanami::Interactor
|
275
|
+
#
|
276
|
+
# def initialize(params)
|
277
|
+
# @params = params
|
278
|
+
# @email_test = EmailTest.new(@params)
|
279
|
+
# end
|
280
|
+
#
|
281
|
+
# def call
|
282
|
+
# persist_email_test!
|
283
|
+
# capture_screenshot!
|
284
|
+
# end
|
285
|
+
#
|
286
|
+
# private
|
287
|
+
# def persist_email_test!
|
288
|
+
# @email_test = EmailTestRepository.persist(@email_test)
|
289
|
+
# end
|
290
|
+
#
|
291
|
+
# # IF THIS RAISES AN EXCEPTION WE FORCE A FAILURE
|
292
|
+
# def capture_screenshot!
|
293
|
+
# Screenshot.new(@email_test).capture!
|
294
|
+
# rescue
|
295
|
+
# fail!
|
296
|
+
# end
|
297
|
+
# end
|
298
|
+
#
|
299
|
+
# result = CreateEmailTest.new(account_id: 1).call
|
300
|
+
# result.success? # => false
|
301
|
+
def fail!
|
302
|
+
@__result.fail!
|
303
|
+
throw :fail
|
304
|
+
end
|
305
|
+
|
306
|
+
# Log an error without interrupting the flow.
|
307
|
+
#
|
308
|
+
# When used, the returned result won't be successful.
|
309
|
+
#
|
310
|
+
# @param message [String] the error message
|
311
|
+
#
|
312
|
+
# @return false
|
313
|
+
#
|
314
|
+
# @since 0.3.5
|
315
|
+
#
|
316
|
+
# @see Hanami::Interactor#error!
|
317
|
+
#
|
318
|
+
# @example
|
319
|
+
# require 'hanami/interactor'
|
320
|
+
#
|
321
|
+
# class CreateRecord
|
322
|
+
# include Hanami::Interactor
|
323
|
+
# expose :logger
|
324
|
+
#
|
325
|
+
# def initialize
|
326
|
+
# @logger = []
|
327
|
+
# end
|
328
|
+
#
|
329
|
+
# def call
|
330
|
+
# prepare_data!
|
331
|
+
# persist!
|
332
|
+
# sync!
|
333
|
+
# end
|
334
|
+
#
|
335
|
+
# private
|
336
|
+
# def prepare_data!
|
337
|
+
# @logger << __method__
|
338
|
+
# error "Prepare data error"
|
339
|
+
# end
|
340
|
+
#
|
341
|
+
# def persist!
|
342
|
+
# @logger << __method__
|
343
|
+
# error "Persist error"
|
344
|
+
# end
|
345
|
+
#
|
346
|
+
# def sync!
|
347
|
+
# @logger << __method__
|
348
|
+
# end
|
349
|
+
# end
|
350
|
+
#
|
351
|
+
# result = CreateRecord.new.call
|
352
|
+
# result.success? # => false
|
353
|
+
#
|
354
|
+
# result.errors # => ["Prepare data error", "Persist error"]
|
355
|
+
# result.logger # => [:prepare_data!, :persist!, :sync!]
|
356
|
+
def error(message)
|
357
|
+
@__result.add_error message
|
358
|
+
false
|
359
|
+
end
|
360
|
+
|
361
|
+
# Log an error AND interrupting the flow.
|
362
|
+
#
|
363
|
+
# When used, the returned result won't be successful.
|
364
|
+
#
|
365
|
+
# @param message [String] the error message
|
366
|
+
#
|
367
|
+
# @since 0.3.5
|
368
|
+
#
|
369
|
+
# @see Hanami::Interactor#error
|
370
|
+
#
|
371
|
+
# @example
|
372
|
+
# require 'hanami/interactor'
|
373
|
+
#
|
374
|
+
# class CreateRecord
|
375
|
+
# include Hanami::Interactor
|
376
|
+
# expose :logger
|
377
|
+
#
|
378
|
+
# def initialize
|
379
|
+
# @logger = []
|
380
|
+
# end
|
381
|
+
#
|
382
|
+
# def call
|
383
|
+
# prepare_data!
|
384
|
+
# persist!
|
385
|
+
# sync!
|
386
|
+
# end
|
387
|
+
#
|
388
|
+
# private
|
389
|
+
# def prepare_data!
|
390
|
+
# @logger << __method__
|
391
|
+
# error "Prepare data error"
|
392
|
+
# end
|
393
|
+
#
|
394
|
+
# def persist!
|
395
|
+
# @logger << __method__
|
396
|
+
# error! "Persist error"
|
397
|
+
# end
|
398
|
+
#
|
399
|
+
# # THIS WILL NEVER BE INVOKED BECAUSE WE USE #error! IN #persist!
|
400
|
+
# def sync!
|
401
|
+
# @logger << __method__
|
402
|
+
# end
|
403
|
+
# end
|
404
|
+
#
|
405
|
+
# result = CreateRecord.new.call
|
406
|
+
# result.success? # => false
|
407
|
+
#
|
408
|
+
# result.errors # => ["Prepare data error", "Persist error"]
|
409
|
+
# result.logger # => [:prepare_data!, :persist!]
|
410
|
+
def error!(message)
|
411
|
+
error(message)
|
412
|
+
fail!
|
413
|
+
end
|
414
|
+
|
415
|
+
# @since 0.3.5
|
416
|
+
# @api private
|
417
|
+
def _call
|
418
|
+
catch :fail do
|
419
|
+
validate!
|
420
|
+
yield
|
421
|
+
end
|
422
|
+
|
423
|
+
_prepare!
|
424
|
+
end
|
425
|
+
|
426
|
+
# @since 0.3.5
|
427
|
+
def validate!
|
428
|
+
fail! unless valid?
|
429
|
+
end
|
430
|
+
|
431
|
+
# @since 0.3.5
|
432
|
+
# @api private
|
433
|
+
def _prepare!
|
434
|
+
@__result.prepare!(_exposures)
|
435
|
+
end
|
436
|
+
|
437
|
+
# @since 0.5.0
|
438
|
+
# @api private
|
439
|
+
def _exposures
|
440
|
+
Hash[].tap do |result|
|
441
|
+
self.class.exposures.each do |name, ivar|
|
442
|
+
result[name] = instance_variable_get(ivar)
|
443
|
+
end
|
444
|
+
end
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
# @since 0.5.0
|
449
|
+
# @api private
|
450
|
+
module ClassMethods
|
451
|
+
# @since 0.5.0
|
452
|
+
# @api private
|
453
|
+
def self.extended(interactor)
|
454
|
+
interactor.class_eval do
|
455
|
+
include Utils::ClassAttribute
|
456
|
+
|
457
|
+
class_attribute :exposures
|
458
|
+
self.exposures = Utils::Hash.new
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
# Expose local instance variables into the returing value of <tt>#call</tt>
|
463
|
+
#
|
464
|
+
# @param instance_variable_names [Symbol,Array<Symbol>] one or more instance
|
465
|
+
# variable names
|
466
|
+
#
|
467
|
+
# @since 0.5.0
|
468
|
+
#
|
469
|
+
# @see Hanami::Interactor::Result
|
470
|
+
#
|
471
|
+
# @example Expose instance variable
|
472
|
+
#
|
473
|
+
# class Signup
|
474
|
+
# include Hanami::Interactor
|
475
|
+
# expose :user
|
476
|
+
#
|
477
|
+
# def initialize(params)
|
478
|
+
# @params = params
|
479
|
+
# @user = User.new(@params[:user])
|
480
|
+
# end
|
481
|
+
#
|
482
|
+
# def call
|
483
|
+
# # ...
|
484
|
+
# end
|
485
|
+
# end
|
486
|
+
#
|
487
|
+
# result = Signup.new(user: { name: "Luca" }).call
|
488
|
+
#
|
489
|
+
# result.user # => #<User:0x007fa85c58ccd8 @name="Luca">
|
490
|
+
# result.params # => NoMethodError
|
491
|
+
def expose(*instance_variable_names)
|
492
|
+
instance_variable_names.each do |name|
|
493
|
+
exposures[name] = "@#{ name }"
|
494
|
+
end
|
495
|
+
end
|
496
|
+
end
|
497
|
+
end
|