augmented 0.2.2 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
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