augmented 0.2.1 → 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +15 -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/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 +24 -45
- 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: cd88ac261436008274986613fc7ce91c1874b454b380e295f7acc5a43831e223
|
4
|
+
data.tar.gz: 77826a1b98d4b243c87b646941c164601f628a03ceee802ab2e44acb982c7894
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87e68662e972f392fca81ad431f2a7b7c712ae25eb28ba251a2663e2aa89d1f2223bac2d5962426c0d6dde6aadf14347b5c7664ea0150691c8e2634075c701e0
|
7
|
+
data.tar.gz: 73e6fb575d524ccde9a3a545334a2159b961d07430d042aefcb114dcfbb7e06c3b7ba5776a94d3c1a7f1669971f4f335a7c6a365e91c3bd5f459000d2c504ad2
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
## [Unreleased]
|
2
|
+
|
3
|
+
## [0.2.6] - 2021-06-23
|
4
|
+
|
5
|
+
- Fixed `String#blank?` not working on Ruby 2.3.
|
6
|
+
|
7
|
+
## [0.2.5] - 2021-05-30
|
8
|
+
|
9
|
+
- Added `Exception#details`, `Exception#details=`, `Exception#detailed`
|
10
|
+
- Added `Exception#chain`
|
11
|
+
- Added `Exception#to_h`
|
12
|
+
|
13
|
+
## [0.2.3] - 2021-05-29
|
14
|
+
|
15
|
+
- 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
|