augmented 0.2.0 → 0.2.5
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 +5 -5
- data/CHANGELOG.md +11 -0
- data/README.md +132 -28
- data/augmented.gemspec +14 -8
- data/lib/augmented.rb +4 -0
- data/lib/augmented/arrays/tieable.rb +1 -1
- data/lib/augmented/enumerators/indexing.rb +3 -1
- data/lib/augmented/exceptions.rb +11 -0
- data/lib/augmented/exceptions/chain.rb +16 -0
- data/lib/augmented/exceptions/detailed.rb +22 -0
- data/lib/augmented/exceptions/serializable.rb +25 -0
- data/lib/augmented/objects/pickable.rb +2 -2
- data/lib/augmented/procs.rb +2 -2
- data/lib/augmented/procs/rescuable.rb +3 -3
- data/lib/augmented/strings.rb +9 -0
- data/lib/augmented/strings/blank.rb +15 -0
- data/lib/augmented/strings/truncatable.rb +20 -0
- data/lib/augmented/version.rb +1 -1
- metadata +26 -47
- data/test/augmented/arrays/tieable_test.rb +0 -66
- data/test/augmented/enumerators/indexing_test.rb +0 -15
- data/test/augmented/hashes/mappable_test.rb +0 -37
- data/test/augmented/hashes/polymorphable_test.rb +0 -45
- data/test/augmented/hashes/transformable_test.rb +0 -87
- data/test/augmented/modules/refined_test.rb +0 -27
- data/test/augmented/objects/iffy_test.rb +0 -69
- data/test/augmented/objects/pickable_test.rb +0 -39
- data/test/augmented/objects/tackable_test.rb +0 -25
- data/test/augmented/objects/tappable_test.rb +0 -141
- data/test/augmented/objects/thru_test.rb +0 -98
- data/test/augmented/procs/chainable_test.rb +0 -22
- data/test/augmented/procs/rescuable_test.rb +0 -38
- data/test/augmented/symbols/arguable_test.rb +0 -51
- data/test/augmented/symbols/comparing_test.rb +0 -131
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 02a3d4fd8fbc13022569168b89c6fb60b575dea7030a6c36b1457a049c468b62
|
|
4
|
+
data.tar.gz: bb89fe218a192cb1eb72f9456988a65c08eec651fc6e3f89e62941e9632dac9a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c4f04bc92e1bdfbff68e62283bfb16b7f8499297916c208ae62156e84d1358efdf4a94f56cb5d0d0123ea985a7f315126026147b82e338e6fea7d4ddcbff489f
|
|
7
|
+
data.tar.gz: 99d873ac314d8ff5a8cc7bf6f6fc5a47cfb27080dbf69167c2a6f6f0509175e6f7cd4c6ab23c2a41a7f73cbd8a5b39cda20c473d1448228dd0316013b7659ae9
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
## [Unreleased]
|
|
2
|
+
|
|
3
|
+
## [0.2.5] - 2021-05-30
|
|
4
|
+
|
|
5
|
+
- Added `Exception#details`, `Exception#details=`, `Exception#detailed`
|
|
6
|
+
- Added `Exception#chain`
|
|
7
|
+
- Added `Exception#to_h`
|
|
8
|
+
|
|
9
|
+
## [0.2.3] - 2021-05-29
|
|
10
|
+
|
|
11
|
+
- Added `String#truncate`, `String#truncate!` and `String#blank?`
|
data/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
`Augmented` is a library with some core-type utility methods that I frequently find myself copying across projects. It uses refinements instead of class modification for maximum control and an easy sleep at night.
|
|
4
4
|
|
|
5
|
-
Many of the methods in `Augmented` facilitate a more functional style of programming and cover a few tiny gaps in Ruby's solid functional support.
|
|
5
|
+
Many of the methods in `Augmented` facilitate a more functional style of programming and cover a few tiny gaps in Ruby's solid functional support.
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
## Installation
|
|
@@ -31,10 +31,12 @@ You can load all refinements for just one type:
|
|
|
31
31
|
```ruby
|
|
32
32
|
using Augmented::Arrays
|
|
33
33
|
using Augmented::Enumerators
|
|
34
|
+
using Augmented::Exceptions
|
|
34
35
|
using Augmented::Hashes
|
|
35
36
|
using Augmented::Modules
|
|
36
37
|
using Augmented::Objects
|
|
37
38
|
using Augmented::Procs
|
|
39
|
+
using Augmented::Strings
|
|
38
40
|
using Augmented::Symbols
|
|
39
41
|
# etc.
|
|
40
42
|
```
|
|
@@ -60,7 +62,7 @@ Weaves an object between the elements of an array. Like `join` but without flatt
|
|
|
60
62
|
```ruby
|
|
61
63
|
using Augmented::Arrays::Tieable
|
|
62
64
|
|
|
63
|
-
[1, 2, 3].tie
|
|
65
|
+
[1, 2, 3].tie(:hello)
|
|
64
66
|
# [1, :hello, 2, :hello, 3]
|
|
65
67
|
|
|
66
68
|
[1, 5, 12].tie{ |a, b| a + b }
|
|
@@ -72,13 +74,88 @@ using Augmented::Arrays::Tieable
|
|
|
72
74
|
|
|
73
75
|
##### `Enumerator#index_by`
|
|
74
76
|
|
|
75
|
-
Builds an index of all elements of an enumerator according to the given criterion.
|
|
77
|
+
Builds an index of all elements of an enumerator according to the given criterion. Last element wins.
|
|
76
78
|
|
|
77
79
|
```ruby
|
|
78
80
|
using Augmented::Enumerators::Indexing
|
|
79
81
|
|
|
80
|
-
['a', 'bb', '
|
|
81
|
-
# {1=>"
|
|
82
|
+
['a', 'bb', 'c', 'ddddd'].to_enum.index_by(&:length)
|
|
83
|
+
# {1=>"c", 2=>"bb", 5=>"ddddd"}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
#### `Augmented::Exceptions`
|
|
88
|
+
|
|
89
|
+
##### `Exception#chain`
|
|
90
|
+
|
|
91
|
+
Returns an enumerator over the exception's causal chain, starting with the exception itself.
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
using Augmented::Exceptions::Chain
|
|
95
|
+
|
|
96
|
+
begin
|
|
97
|
+
begin
|
|
98
|
+
begin
|
|
99
|
+
raise 'first'
|
|
100
|
+
rescue
|
|
101
|
+
raise 'second'
|
|
102
|
+
end
|
|
103
|
+
rescue
|
|
104
|
+
raise 'third'
|
|
105
|
+
end
|
|
106
|
+
rescue => error
|
|
107
|
+
error.chain.map(&:message)
|
|
108
|
+
end
|
|
109
|
+
# ["third", "second", "first"]
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
##### `Exception#details`, `Exception#details=`, `Exception#detailed`
|
|
114
|
+
|
|
115
|
+
Attach a hash of details to any exception.
|
|
116
|
+
|
|
117
|
+
```ruby
|
|
118
|
+
using Augmented::Exceptions::Detailed
|
|
119
|
+
|
|
120
|
+
exception = RuntimeError.new('oops!').detailed(foo: 10, bar: { baz: 30 })
|
|
121
|
+
exception.details
|
|
122
|
+
# {:foo=>10, :bar=>{:baz=>30}}
|
|
123
|
+
exception.details = { bam: 40 }
|
|
124
|
+
exception.details
|
|
125
|
+
# {:bam=>40}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
##### `Exception#to_h`
|
|
130
|
+
|
|
131
|
+
Serializes an exception into a Hash including its backtrace, details and causal chain.
|
|
132
|
+
|
|
133
|
+
```ruby
|
|
134
|
+
using Augmented::Exceptions::Serializable
|
|
135
|
+
using Augmented::Exceptions::Detailed
|
|
136
|
+
|
|
137
|
+
begin
|
|
138
|
+
begin
|
|
139
|
+
raise RuntimeError.new('first').detailed(foo: 10)
|
|
140
|
+
rescue
|
|
141
|
+
raise RuntimeError.new('second').detailed(bar: 20)
|
|
142
|
+
end
|
|
143
|
+
rescue => error
|
|
144
|
+
error.to_h
|
|
145
|
+
end
|
|
146
|
+
# {
|
|
147
|
+
# :class => "RuntimeError",
|
|
148
|
+
# :message => "second",
|
|
149
|
+
# :details => { :bar => 20 },
|
|
150
|
+
# :backtrace => [ ... ],
|
|
151
|
+
# :cause => {
|
|
152
|
+
# :class => "RuntimeError",
|
|
153
|
+
# :message => "first",
|
|
154
|
+
# :details => { :foo => 10 },
|
|
155
|
+
# :backtrace => [ ... ],
|
|
156
|
+
# :cause => nil
|
|
157
|
+
# }
|
|
158
|
+
# }
|
|
82
159
|
```
|
|
83
160
|
|
|
84
161
|
|
|
@@ -149,21 +226,16 @@ tree.transform({ lorem: :upcase, dolor: { sit: triple } })
|
|
|
149
226
|
Makes it less verbose to create small refinements.
|
|
150
227
|
|
|
151
228
|
```ruby
|
|
152
|
-
using Augmented::
|
|
229
|
+
using Augmented::Modules::Refined
|
|
153
230
|
|
|
154
231
|
class TextPage
|
|
155
232
|
using refined String,
|
|
156
|
-
|
|
157
|
-
fill: -> filler { (filler * self.length)[0..length] }
|
|
233
|
+
to_phrase: -> { self.strip.capitalize.gsub(/\.?\z/, '.') }
|
|
158
234
|
|
|
159
235
|
# ...
|
|
160
236
|
|
|
161
237
|
def text
|
|
162
|
-
@
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
def obscured_text
|
|
166
|
-
text.fill '?'
|
|
238
|
+
@lines.map(&:to_phrase).join(' ')
|
|
167
239
|
end
|
|
168
240
|
end
|
|
169
241
|
```
|
|
@@ -178,11 +250,11 @@ Allows you to conditionally return an object, allowing you to be more concise in
|
|
|
178
250
|
```ruby
|
|
179
251
|
using Augmented::Objects::Iffy
|
|
180
252
|
|
|
181
|
-
Person.new.eat
|
|
182
|
-
Person.new.eat
|
|
253
|
+
Person.new.eat(toast.if(toast.buttered?).else(muffin))
|
|
254
|
+
Person.new.eat(toast.if(&:buttered?).else(muffin))
|
|
183
255
|
|
|
184
|
-
Person.new.eat
|
|
185
|
-
Person.new.eat
|
|
256
|
+
Person.new.eat(toast.unless(toast.soggy?).else(muffin))
|
|
257
|
+
Person.new.eat(toast.unless(&:soggy?).else(muffin))
|
|
186
258
|
```
|
|
187
259
|
|
|
188
260
|
##### `Object#pick`
|
|
@@ -193,13 +265,13 @@ Calls a bunch of methods on an object and collects the results.
|
|
|
193
265
|
using Augmented::Objects::Pickable
|
|
194
266
|
|
|
195
267
|
class MyThing
|
|
196
|
-
def
|
|
197
|
-
def
|
|
198
|
-
def
|
|
268
|
+
def foo; 'lorem'; end
|
|
269
|
+
def bar; 'ipsum'; end
|
|
270
|
+
def baz; 'dolor'; end
|
|
199
271
|
end
|
|
200
272
|
|
|
201
|
-
MyThing.new.pick
|
|
202
|
-
# {:
|
|
273
|
+
MyThing.new.pick(:foo, :baz)
|
|
274
|
+
# {:foo=>"lorem", :baz=>"dolor"}
|
|
203
275
|
```
|
|
204
276
|
|
|
205
277
|
##### `Object#tack`
|
|
@@ -209,8 +281,8 @@ Appends a bunch of singleton methods to an object.
|
|
|
209
281
|
```ruby
|
|
210
282
|
using Augmented::Objects::Tackable
|
|
211
283
|
|
|
212
|
-
Object.new.tack(
|
|
213
|
-
# hello I'm
|
|
284
|
+
Object.new.tack(name: 'Alice', greet: -> { puts "hello I'm #{name}" }).greet
|
|
285
|
+
# hello I'm Alice
|
|
214
286
|
```
|
|
215
287
|
|
|
216
288
|
##### `Object#tap_if`, `Object#tap_unless`
|
|
@@ -269,13 +341,45 @@ Wraps a `Proc` to rescue it from certain exceptions while returning a given valu
|
|
|
269
341
|
```ruby
|
|
270
342
|
using Augmented::Procs::Rescuable
|
|
271
343
|
|
|
272
|
-
integerify = proc{ |x| Integer(x) }.rescues
|
|
344
|
+
integerify = proc{ |x| Integer(x) }.rescues(ArgumentError, 42)
|
|
273
345
|
|
|
274
|
-
['1', '2', '
|
|
346
|
+
['1', '2', 'oops!', '4'].map(&integerify)
|
|
275
347
|
# [1, 2, 42, 4]
|
|
276
348
|
```
|
|
277
349
|
|
|
278
350
|
|
|
351
|
+
#### `Augmented::Strings`
|
|
352
|
+
|
|
353
|
+
##### `String#blank?`
|
|
354
|
+
|
|
355
|
+
Tests if a string is empty or made of whitespace.
|
|
356
|
+
|
|
357
|
+
```ruby
|
|
358
|
+
using Augmented::Strings::Blank
|
|
359
|
+
|
|
360
|
+
''.blank?
|
|
361
|
+
# true
|
|
362
|
+
' '.blank?
|
|
363
|
+
# true
|
|
364
|
+
' hello '.blank?
|
|
365
|
+
# false
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
##### `String#truncate`, `String#truncate!`
|
|
370
|
+
|
|
371
|
+
Returns a prefix of a string up to a given number of characters.
|
|
372
|
+
|
|
373
|
+
```ruby
|
|
374
|
+
using Augmented::Strings::Truncatable
|
|
375
|
+
|
|
376
|
+
'hello world'.truncate(5)
|
|
377
|
+
# "hello"
|
|
378
|
+
[(string = 'hello world'), string.truncate!(5)]
|
|
379
|
+
# ["hello", "hello"]
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
|
|
279
383
|
#### `Augmented::Symbols`
|
|
280
384
|
|
|
281
385
|
##### `Symbol#with`
|
|
@@ -311,8 +415,8 @@ end
|
|
|
311
415
|
|
|
312
416
|
users = [ User.new('Marianne'), User.new('Jeremy') ]
|
|
313
417
|
|
|
314
|
-
users.find
|
|
315
|
-
# <User:0x... name='Marianne'>
|
|
418
|
+
users.find(&:name.eq('Marianne'))
|
|
419
|
+
# <User:0x... @name='Marianne'>
|
|
316
420
|
```
|
|
317
421
|
|
|
318
422
|
|
data/augmented.gemspec
CHANGED
|
@@ -6,18 +6,24 @@ require 'augmented/version'
|
|
|
6
6
|
Gem::Specification.new do |spec|
|
|
7
7
|
spec.name = "augmented"
|
|
8
8
|
spec.version = Augmented::VERSION
|
|
9
|
-
spec.authors = ["
|
|
10
|
-
spec.email = ["bruno@brunze.com"]
|
|
9
|
+
spec.authors = ["brunze"]
|
|
11
10
|
spec.summary = %q{Useful extra methods for some Ruby core types.}
|
|
12
11
|
spec.description = %q{Adds a few useful extra methods to some of Ruby's core types, available as refinements.}
|
|
13
12
|
spec.homepage = "https://github.com/brunze/augmented"
|
|
14
13
|
spec.license = "MIT"
|
|
15
14
|
|
|
16
|
-
spec.
|
|
17
|
-
spec.
|
|
18
|
-
spec.
|
|
19
|
-
spec.require_paths = ["lib"]
|
|
15
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
|
16
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
|
17
|
+
spec.metadata['changelog_uri'] = spec.homepage + '/CHANGELOG.md'
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
# Specify which files should be added to the gem when it is released.
|
|
20
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
21
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
22
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
|
23
|
+
end
|
|
24
|
+
spec.bindir = 'bin'
|
|
25
|
+
spec.require_paths = ['lib']
|
|
26
|
+
|
|
27
|
+
spec.add_development_dependency "bundler", "~> 2"
|
|
28
|
+
spec.add_development_dependency "rake", ">= 13.0.3"
|
|
23
29
|
end
|
data/lib/augmented.rb
CHANGED
|
@@ -2,18 +2,22 @@ require 'augmented/version'
|
|
|
2
2
|
|
|
3
3
|
require 'augmented/arrays'
|
|
4
4
|
require 'augmented/enumerators'
|
|
5
|
+
require 'augmented/exceptions'
|
|
5
6
|
require 'augmented/hashes'
|
|
6
7
|
require 'augmented/modules'
|
|
7
8
|
require 'augmented/objects'
|
|
8
9
|
require 'augmented/procs'
|
|
10
|
+
require 'augmented/strings'
|
|
9
11
|
require 'augmented/symbols'
|
|
10
12
|
|
|
11
13
|
module Augmented
|
|
12
14
|
include Arrays
|
|
13
15
|
include Enumerators
|
|
16
|
+
include Exceptions
|
|
14
17
|
include Hashes
|
|
15
18
|
include Modules
|
|
16
19
|
include Objects
|
|
17
20
|
include Procs
|
|
21
|
+
include Strings
|
|
18
22
|
include Symbols
|
|
19
23
|
end
|
|
@@ -7,7 +7,7 @@ module Augmented
|
|
|
7
7
|
raise ArgumentError, 'you must provide a non-nil tie object or block' if object.nil? && !block_given?
|
|
8
8
|
|
|
9
9
|
tie_function = block_given? ? block : proc{ object }
|
|
10
|
-
ties = self.each_cons(2).map
|
|
10
|
+
ties = self.each_cons(2).map(&tie_function)
|
|
11
11
|
|
|
12
12
|
self.zip(ties).flatten(1)[0...-1]
|
|
13
13
|
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Augmented
|
|
2
|
+
module Exceptions
|
|
3
|
+
module Chain
|
|
4
|
+
refine Exception do
|
|
5
|
+
|
|
6
|
+
def chain
|
|
7
|
+
Enumerator.new do |yielder|
|
|
8
|
+
yielder << exception = self
|
|
9
|
+
yielder << exception while exception = exception.cause
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Augmented
|
|
2
|
+
module Exceptions
|
|
3
|
+
module Detailed
|
|
4
|
+
refine Exception do
|
|
5
|
+
|
|
6
|
+
def details
|
|
7
|
+
@_details ||= {}
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def details= **details
|
|
11
|
+
@_details = details
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def detailed **details
|
|
15
|
+
self.details = details
|
|
16
|
+
self
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Augmented
|
|
2
|
+
module Exceptions
|
|
3
|
+
module Serializable
|
|
4
|
+
refine Exception do
|
|
5
|
+
using Chain
|
|
6
|
+
using Detailed
|
|
7
|
+
|
|
8
|
+
def to_h
|
|
9
|
+
self.chain.map do |exception|
|
|
10
|
+
{
|
|
11
|
+
class: exception.class.name,
|
|
12
|
+
message: exception.message,
|
|
13
|
+
details: exception.details,
|
|
14
|
+
backtrace: exception.backtrace || [],
|
|
15
|
+
cause: nil,
|
|
16
|
+
}
|
|
17
|
+
end.reverse.reduce do |cause, exception|
|
|
18
|
+
exception.merge!(cause: cause)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -7,14 +7,14 @@ module Augmented
|
|
|
7
7
|
ensure_array = -> thing { thing.kind_of?(Array) ? thing : Array[thing] }
|
|
8
8
|
|
|
9
9
|
if self.respond_to? :each
|
|
10
|
-
self.map{ |thing| thing.pick
|
|
10
|
+
self.map{ |thing| thing.pick(*picks) }
|
|
11
11
|
else
|
|
12
12
|
picks.each_with_object({}) do |pick, result|
|
|
13
13
|
|
|
14
14
|
if pick.kind_of? Hash
|
|
15
15
|
|
|
16
16
|
pick.each do |attribute, nested_picks|
|
|
17
|
-
result[attribute] = self.__send__(attribute.to_sym).pick
|
|
17
|
+
result[attribute] = self.__send__(attribute.to_sym).pick(*ensure_array[nested_picks])
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
else
|