augmented 0.2.2 → 0.2.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d8cd8a8566eb16186e26909a2c32597cb2cf8d0e12e2f6785a55fa2cc43992ab
4
- data.tar.gz: b19a9fd510664c6dc52e99b98ebf0faa5bc70c8c061143b7c4e57addb84f261f
3
+ metadata.gz: 6d65d68527ff708f00861bd8c107acfde5f7ce813ab5a3f6b88a8d9c12a331ad
4
+ data.tar.gz: 2d1c9fe2af451feb5c9eda30aee3514304e4ba62e0baf0d38475a3093389a4d4
5
5
  SHA512:
6
- metadata.gz: de5a4fde6a7325acd6d90008bd4f7895da85a87b71691d4c7cc5cbb81b798576f46b34621cbd9f0857c6ae087ab7e684855d839b97885ad7f127118a00e92f88
7
- data.tar.gz: f6185c773e2af7676f35e07d0732305bfc7c5882109a0248db835c77ebd41c361ee8946cc66dcdced3b3087fcfc14b8c6953299eea677e8b08019f70983323cd
6
+ metadata.gz: 907238de8dda6ab6a1403a43ea31bdc3c7a7315d3c951a62434da1bc91ff932df1111e141ffdef65fd12d7d447c67151d3745e823ba2bbdceeff246f0bea57cf
7
+ data.tar.gz: 8ab148a0c46b387f722041efd2a73aeff7c02e3e939ff1e1edf92c013ab935a08b5c8928bc4becf238f56307e0e7b6099d04b9be64408ba18ed25297577ed21c
data/CHANGELOG.md ADDED
@@ -0,0 +1,20 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.2.7] - 2021-06-26
4
+
5
+ - Added `String#squish` and `String#squish!`.
6
+ - Added `Object#in?`.
7
+
8
+ ## [0.2.6] - 2021-06-23
9
+
10
+ - Fixed `String#blank?` not working on Ruby 2.3.
11
+
12
+ ## [0.2.5] - 2021-05-30
13
+
14
+ - Added `Exception#details`, `Exception#details=`, `Exception#detailed`
15
+ - Added `Exception#chain`
16
+ - Added `Exception#to_h`
17
+
18
+ ## [0.2.3] - 2021-05-29
19
+
20
+ - Added `String#truncate`, `String#truncate!` and `String#blank?`
data/README.md CHANGED
@@ -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 :hello
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', 'ccccc'].to_enum.index_by(&:length)
81
- # {1=>"a", 2=>"bb", 5=>"ccccc"}
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::Hashes::Transformable
229
+ using Augmented::Modules::Refined
153
230
 
154
231
  class TextPage
155
232
  using refined String,
156
- as_phrase: -> { self.strip.capitalize.gsub /\.?\z/, '.' },
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
- @strings.map(&:as_phrase).join ' '
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,26 @@ 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 toast.if(toast.buttered?).else(muffin)
182
- Person.new.eat toast.if(&:buttered?).else(muffin)
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 toast.unless(toast.soggy?).else(muffin)
185
- Person.new.eat toast.unless(&:soggy?).else(muffin)
256
+ Person.new.eat(toast.unless(toast.soggy?).else(muffin))
257
+ Person.new.eat(toast.unless(&:soggy?).else(muffin))
258
+ ```
259
+
260
+ ##### `Object#in?`
261
+
262
+ Tests if the object is included in a collection (collection must respond to `included?`).
263
+
264
+ ```ruby
265
+ using Augmented::Objects::In
266
+
267
+ 2.in?([1, 2, 3])
268
+ # true
269
+ 5.in?(0..2)
270
+ # false
271
+ 'B'.in?('ABC')
272
+ # true
186
273
  ```
187
274
 
188
275
  ##### `Object#pick`
@@ -193,13 +280,13 @@ Calls a bunch of methods on an object and collects the results.
193
280
  using Augmented::Objects::Pickable
194
281
 
195
282
  class MyThing
196
- def lorem; 'hello'; end
197
- def ipsum; 'cruel'; end
198
- def dolor; 'world'; end
283
+ def foo; 'lorem'; end
284
+ def bar; 'ipsum'; end
285
+ def baz; 'dolor'; end
199
286
  end
200
287
 
201
- MyThing.new.pick :lorem, :dolor
202
- # {:lorem=>"hello", :dolor=>"world"}
288
+ MyThing.new.pick(:foo, :baz)
289
+ # {:foo=>"lorem", :baz=>"dolor"}
203
290
  ```
204
291
 
205
292
  ##### `Object#tack`
@@ -209,8 +296,8 @@ Appends a bunch of singleton methods to an object.
209
296
  ```ruby
210
297
  using Augmented::Objects::Tackable
211
298
 
212
- Object.new.tack(id: 11, greet: -> { puts "hello I'm #{id}" }).greet
213
- # hello I'm 11
299
+ Object.new.tack(name: 'Alice', greet: -> { puts "hello I'm #{name}" }).greet
300
+ # hello I'm Alice
214
301
  ```
215
302
 
216
303
  ##### `Object#tap_if`, `Object#tap_unless`
@@ -269,13 +356,60 @@ Wraps a `Proc` to rescue it from certain exceptions while returning a given valu
269
356
  ```ruby
270
357
  using Augmented::Procs::Rescuable
271
358
 
272
- integerify = proc{ |x| Integer(x) }.rescues ArgumentError, 42
359
+ integerify = proc{ |x| Integer(x) }.rescues(ArgumentError, 42)
273
360
 
274
- ['1', '2', 'abc', '4'].map &integerify
361
+ ['1', '2', 'oops!', '4'].map(&integerify)
275
362
  # [1, 2, 42, 4]
276
363
  ```
277
364
 
278
365
 
366
+ #### `Augmented::Strings`
367
+
368
+ ##### `String#blank?`
369
+
370
+ Tests if a string is empty or made of whitespace.
371
+
372
+ ```ruby
373
+ using Augmented::Strings::Blank
374
+
375
+ ''.blank?
376
+ # true
377
+ ' '.blank?
378
+ # true
379
+ ' hello '.blank?
380
+ # false
381
+ ```
382
+
383
+
384
+ ##### `String#squish`, `String#squish!`
385
+
386
+ Replaces runs of whitespace with a single space except at the edges of the string. Can be given a custom pattern and replacement.
387
+
388
+ ```ruby
389
+ using Augmented::Strings::Squish
390
+
391
+ ' hello world '.squish!
392
+ # "hello world"
393
+
394
+ '---what-a-nice--kebab-'.squish(/\W+/, '_')
395
+ # "what_a_nice_kebab"
396
+ ```
397
+
398
+
399
+ ##### `String#truncate`, `String#truncate!`
400
+
401
+ Returns a prefix of a string up to a given number of characters.
402
+
403
+ ```ruby
404
+ using Augmented::Strings::Truncatable
405
+
406
+ 'hello world'.truncate(5)
407
+ # "hello"
408
+ [(string = 'hello world'), string.truncate!(5)]
409
+ # ["hello", "hello"]
410
+ ```
411
+
412
+
279
413
  #### `Augmented::Symbols`
280
414
 
281
415
  ##### `Symbol#with`
@@ -311,8 +445,8 @@ end
311
445
 
312
446
  users = [ User.new('Marianne'), User.new('Jeremy') ]
313
447
 
314
- users.find &(:name.eq 'Marianne')
315
- # <User:0x... name='Marianne'>
448
+ users.find(&:name.eq('Marianne'))
449
+ # <User:0x... @name='Marianne'>
316
450
  ```
317
451
 
318
452
 
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 = ["bruno"]
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.files = `git ls-files -z`.split("\x0")
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"]
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
- spec.add_development_dependency "bundler", "~> 2.1"
22
- spec.add_development_dependency "rake", ">= 12.3.3"
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
@@ -4,7 +4,9 @@ module Augmented
4
4
  refine Enumerator do
5
5
 
6
6
  def index_by &criterion
7
- Hash[ self.map(&criterion).zip(self) ]
7
+ self.each_with_object({}) do |element, index|
8
+ index[criterion.(element)] = element
9
+ end
8
10
  end
9
11
 
10
12
  end
@@ -0,0 +1,11 @@
1
+ require 'augmented/exceptions/chain'
2
+ require 'augmented/exceptions/detailed'
3
+ require 'augmented/exceptions/serializable'
4
+
5
+ module Augmented
6
+ module Exceptions
7
+ include Chain
8
+ include Detailed
9
+ include Serializable
10
+ end
11
+ 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