fat_core 7.1.3 → 7.2.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/.gitignore +1 -1
- data/.yardopts +3 -4
- data/Gemfile +1 -0
- data/README.md +1199 -0
- data/README.org +266 -225
- data/Rakefile +3 -7
- data/lib/fat_core/all.rb +1 -0
- data/lib/fat_core/string.rb +34 -13
- data/lib/fat_core/version.rb +2 -2
- data/lib/fat_core.rb +12 -2
- data/spec/lib/string_spec.rb +9 -0
- metadata +3 -2
data/README.md
ADDED
|
@@ -0,0 +1,1199 @@
|
|
|
1
|
+
- [Version](#org706993f)
|
|
2
|
+
- [Introduction](#org8e3de1e)
|
|
3
|
+
- [Installation](#orge71ccdc)
|
|
4
|
+
- [Usage](#org1ef61a0)
|
|
5
|
+
- [Array](#orgfc24a05)
|
|
6
|
+
- [Method `#comma_join(sep: nil, last_sep: nil, two_sep: nil)`](#org779ed95)
|
|
7
|
+
- [Method `#last_i`](#org07f787c)
|
|
8
|
+
- [Method `#intersect_with_dups`](#org0d2857b)
|
|
9
|
+
- [Method `diff_with_dups`](#org83423fa)
|
|
10
|
+
- [BigDecimal `#inspect`](#orgf77f8a1)
|
|
11
|
+
- [Enumerable](#orgdce8ffe)
|
|
12
|
+
- [Method `#each_with_flags`](#org166e57c)
|
|
13
|
+
- [Hash](#org1e11773)
|
|
14
|
+
- [Method `#each_pair_with_flags`](#org0bd20b9)
|
|
15
|
+
- [Method `#delete_with_value` and `#delete_with_value!`](#org4dc0aa1)
|
|
16
|
+
- [Method `#keys_with_value`](#org605ad55)
|
|
17
|
+
- [Method `#remap_keys`](#orgdde4b0b)
|
|
18
|
+
- [Method `#replace_keys`](#org7603809)
|
|
19
|
+
- [Alias `#merge` to `<<`](#orgadf50ea)
|
|
20
|
+
- [Numeric](#org3918509)
|
|
21
|
+
- [Method `#signum`](#org6abf375)
|
|
22
|
+
- [Method `#commas(places = nil)`](#org00c3e90)
|
|
23
|
+
- [Methods `#whole?` and `#int_if_whole`](#orgb844d6f)
|
|
24
|
+
- [Method `#secs_to_hms`](#orgfd1b851)
|
|
25
|
+
- [Range](#org7a70260)
|
|
26
|
+
- [Methods `#contiguous`, `#left_contiguous`, `#right_contiguous`](#orgdd06e2c)
|
|
27
|
+
- [Method `#join(other)`](#org28a7d95)
|
|
28
|
+
- [Method `#spanned_by?(others)`](#org5d367a6)
|
|
29
|
+
- [Methods `#gaps(others)`, `#overlaps(others)`](#orga33fd47)
|
|
30
|
+
- [String](#orgbd1bd5e)
|
|
31
|
+
- [Method `#fuzzy_match`](#org63111cb)
|
|
32
|
+
- [Method `#matches_with`](#orgdae93bf)
|
|
33
|
+
- [Method `#entitle`](#org1a5d1e4)
|
|
34
|
+
- [Method `#distance`](#orgd671ee5)
|
|
35
|
+
- [Method `#commas(places)`](#orgfdd51bd)
|
|
36
|
+
- [Method `#wrap(width, hang)`](#org826950e)
|
|
37
|
+
- [Method `#as_sym`](#orgc017d90)
|
|
38
|
+
- [Method `gut`](#org3459d99)
|
|
39
|
+
- [Symbol](#org2241c53)
|
|
40
|
+
- [Method `#as_str`](#orgf2478cc)
|
|
41
|
+
- [TeX Quoting](#org5620bc3)
|
|
42
|
+
- [Contributing](#orgfe2e72b)
|
|
43
|
+
|
|
44
|
+
[](https://github.com/ddoherty03/fat_core/actions/workflows/ruby.yml)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
<a id="org706993f"></a>
|
|
48
|
+
|
|
49
|
+
# Version
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
"Current version is: #{FatCore::VERSION}"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
Current version is: 7.1.3
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
<a id="org8e3de1e"></a>
|
|
61
|
+
|
|
62
|
+
# Introduction
|
|
63
|
+
|
|
64
|
+
`fat-core` is somewhat of a grab bag of core class extensions that I have found useful across several projects. It's higgeldy-piggeldy nature reflects the fact that none of them are important enough to deserve a gem of their own, but nonetheless need to be collected in one place to reduce redundancy across projects and provide a focused place to develop and test them.
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
<a id="orge71ccdc"></a>
|
|
68
|
+
|
|
69
|
+
# Installation
|
|
70
|
+
|
|
71
|
+
Add this line to your application's Gemfile:
|
|
72
|
+
|
|
73
|
+
```ruby
|
|
74
|
+
gem 'fat_core'
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
And then execute:
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
$ bundle
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Or install it yourself as:
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
$ gem install fat_core
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
<a id="org1ef61a0"></a>
|
|
91
|
+
|
|
92
|
+
# Usage
|
|
93
|
+
|
|
94
|
+
You can extend classes individually by requiring the corresponding file:
|
|
95
|
+
|
|
96
|
+
```ruby
|
|
97
|
+
require 'fat_core/array'
|
|
98
|
+
require 'fat_core/bigdecimal'
|
|
99
|
+
require 'fat_core/enumerable'
|
|
100
|
+
require 'fat_core/hash'
|
|
101
|
+
require 'fat_core/kernel'
|
|
102
|
+
require 'fat_core/numeric'
|
|
103
|
+
require 'fat_core/range'
|
|
104
|
+
require 'fat_core/string'
|
|
105
|
+
require 'fat_core/symbol'
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Or, you can require them all:
|
|
109
|
+
|
|
110
|
+
```ruby
|
|
111
|
+
require 'fat_core/all'
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
false
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Many of these have little that is of general interest, but there are a few goodies.
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
<a id="orgfc24a05"></a>
|
|
122
|
+
|
|
123
|
+
## Array
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
<a id="org779ed95"></a>
|
|
127
|
+
|
|
128
|
+
### Method `#comma_join(sep: nil, last_sep: nil, two_sep: nil)`
|
|
129
|
+
|
|
130
|
+
Convert this array into a single string by (1) applying `#to_s` to each element and (2) joining the elements with the string given by the `sep:` parameter. By default the sep parameter is ', '.
|
|
131
|
+
|
|
132
|
+
You may use a different separation string in the case when there are only two items in the list by supplying a `two_sep` parameter.
|
|
133
|
+
|
|
134
|
+
You may also supply a difference separation string to separate the second-last and last items in the array by supplying a `last_sep:` parameter.
|
|
135
|
+
|
|
136
|
+
By default, the sep parameter is the string ', ', the `two_sep` is ' and ', and the `last_sep` is ', and ', all of which makes for a well-punctuated English clause.
|
|
137
|
+
|
|
138
|
+
If `sep` is given, the other two parameters are set to its value by default. If `last_sep` is given, `two_sep` takes its value by default.
|
|
139
|
+
|
|
140
|
+
If the input array is empty, `#comma_join` returns an empty string.
|
|
141
|
+
|
|
142
|
+
```ruby
|
|
143
|
+
%w{hammers nails glue bolts}.comma_join
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
hammers, nails, glue, and bolts
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
```ruby
|
|
151
|
+
%w{hammers nails}.comma_join
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
hammers and nails
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
And, if you are ideologically opposed to the Oxford comma:
|
|
159
|
+
|
|
160
|
+
```ruby
|
|
161
|
+
%w{hammers nails glue bolts}.comma_join(last_sep: ' and ')
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
hammers, nails, glue and bolts
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
<a id="org07f787c"></a>
|
|
170
|
+
|
|
171
|
+
### Method `#last_i`
|
|
172
|
+
|
|
173
|
+
Return the index of the last element of the Array.
|
|
174
|
+
|
|
175
|
+
```ruby
|
|
176
|
+
%w{hammers nails glue bolts}.last_i
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
3
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
<a id="org0d2857b"></a>
|
|
185
|
+
|
|
186
|
+
### Method `#intersect_with_dups`
|
|
187
|
+
|
|
188
|
+
Return a new Array that is the intersection of this Array with all `others`, but without removing duplicates as the `Array#&` method does. All items of this Array are included in the result but only if they also appear in all of the other Arrays.
|
|
189
|
+
|
|
190
|
+
```ruby
|
|
191
|
+
a = %w{hammers nails glue bolts nails}
|
|
192
|
+
b = %w{nails fingers bolts knuckles nails}
|
|
193
|
+
a.intersect_with_dups(b)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
| nails | bolts | nails |
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
<a id="org83423fa"></a>
|
|
202
|
+
|
|
203
|
+
### Method `diff_with_dups`
|
|
204
|
+
|
|
205
|
+
Return an Array that is the difference between this Array and `other`, but without removing duplicates as the Array#- method does. All items of this Array are included in the result *unless* they also appear in any of the `other` Arrays.
|
|
206
|
+
|
|
207
|
+
```ruby
|
|
208
|
+
a = %w{hammers nails glue bolts hammers nails}
|
|
209
|
+
b = %w{nails fingers knuckles nails}
|
|
210
|
+
a.diff_with_dups(b)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
```
|
|
214
|
+
| hammers | glue | bolts | hammers |
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
<a id="orgf77f8a1"></a>
|
|
219
|
+
|
|
220
|
+
## BigDecimal `#inspect`
|
|
221
|
+
|
|
222
|
+
`FatCore` provides nothing but a better `#inspect` method for the `BigDecimal` class since the default inspect method is not very readable.
|
|
223
|
+
|
|
224
|
+
```ruby
|
|
225
|
+
BigDecimal('2.1718281828').inspect
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
2.1718281828
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Without `FatCore`, the result is "0.2718281828e1", forcing you to interpret the exponent to understand where the decimal place is.
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
<a id="orgdce8ffe"></a>
|
|
236
|
+
|
|
237
|
+
## Enumerable
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
<a id="org166e57c"></a>
|
|
241
|
+
|
|
242
|
+
### Method `#each_with_flags`
|
|
243
|
+
|
|
244
|
+
`FatCore::Enumerable` extends `Enumerable` with the `#each_with_flags` method that yields the elements of the `Enumerable` but also yields two booleans, `first` and `last` that are set to `true` on respectively, the first and last element of the Enumerable and `false` otherwise. This makes it easy to treat these two cases specially without testing the index as in `#each_with_index`.
|
|
245
|
+
|
|
246
|
+
```ruby
|
|
247
|
+
result = []
|
|
248
|
+
fibs = %w{1, 1, 2, 3, 5, 8, 13, 21}
|
|
249
|
+
fibs.each_with_flags do |f, first, last|
|
|
250
|
+
result <<
|
|
251
|
+
if first
|
|
252
|
+
["Start", f]
|
|
253
|
+
elsif last
|
|
254
|
+
["Last", f]
|
|
255
|
+
else
|
|
256
|
+
["Continue", f]
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
result
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
```
|
|
263
|
+
| Start | 1, |
|
|
264
|
+
| Continue | 1, |
|
|
265
|
+
| Continue | 2, |
|
|
266
|
+
| Continue | 3, |
|
|
267
|
+
| Continue | 5, |
|
|
268
|
+
| Continue | 8, |
|
|
269
|
+
| Continue | 13, |
|
|
270
|
+
| Last | 21 |
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
<a id="org1e11773"></a>
|
|
275
|
+
|
|
276
|
+
## Hash
|
|
277
|
+
|
|
278
|
+
FatCore::Hash extends the Hash class with some useful methods.
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
<a id="org0bd20b9"></a>
|
|
282
|
+
|
|
283
|
+
### Method `#each_pair_with_flags`
|
|
284
|
+
|
|
285
|
+
As with the extension for `Enumerables`, `FatCore` provides a method for enumerating the key-value pair of the `Hash` with flags that are set `true` for the first and last elements but `false` otherwise:
|
|
286
|
+
|
|
287
|
+
```ruby
|
|
288
|
+
h = {'Chaucer' => 'Cantebury Tales', 'Shakespeare' => 'The Merchant of Venice',
|
|
289
|
+
'Austen' => 'Pride and Prejudice', 'C. Brontë' => 'Jane Eyre',
|
|
290
|
+
'E. Brontë' => 'Wuthering Heights' }
|
|
291
|
+
result = []
|
|
292
|
+
result << ['Position', 'Author', 'Novel']
|
|
293
|
+
result << nil
|
|
294
|
+
h.each_pair_with_flags do |k, v, first, last|
|
|
295
|
+
pos=
|
|
296
|
+
if first
|
|
297
|
+
'Begin'
|
|
298
|
+
elsif last
|
|
299
|
+
'End'
|
|
300
|
+
else
|
|
301
|
+
'Middle'
|
|
302
|
+
end
|
|
303
|
+
result << [pos, k, v]
|
|
304
|
+
end
|
|
305
|
+
result
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
```
|
|
309
|
+
| Position | Author | Novel |
|
|
310
|
+
|----------+-------------+------------------------|
|
|
311
|
+
| Begin | Chaucer | Cantebury Tales |
|
|
312
|
+
| Middle | Shakespeare | The Merchant of Venice |
|
|
313
|
+
| Middle | Austen | Pride and Prejudice |
|
|
314
|
+
| Middle | C. Brontë | Jane Eyre |
|
|
315
|
+
| End | E. Brontë | Wuthering Heights |
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
<a id="org4dc0aa1"></a>
|
|
320
|
+
|
|
321
|
+
### Method `#delete_with_value` and `#delete_with_value!`
|
|
322
|
+
|
|
323
|
+
This method modifies a `Hash` by deleting the key-value pairs when the value equals the given value or values:
|
|
324
|
+
|
|
325
|
+
```ruby
|
|
326
|
+
h = { a: 1, b: 2, c: 3, d: 2, e: 1 }
|
|
327
|
+
h.delete_with_value!(2)
|
|
328
|
+
puts h
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
```
|
|
332
|
+
{:a=>1, :c=>3, :e=>1}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
You can supply multiple values for deletion:
|
|
336
|
+
|
|
337
|
+
```ruby
|
|
338
|
+
h = { a: 1, b: 2, c: 3, d: 2, e: 1 }
|
|
339
|
+
h.delete_with_value!(1, 3)
|
|
340
|
+
puts h
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
```
|
|
344
|
+
{:b=>2, :d=>2}
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
The non-bang method returns a clone of the Hash with the given deletions made:
|
|
348
|
+
|
|
349
|
+
```ruby
|
|
350
|
+
h = { a: 1, b: 2, c: 3, d: 2, e: 1 }
|
|
351
|
+
h2 = h.delete_with_value(1, 3)
|
|
352
|
+
puts h
|
|
353
|
+
puts h2
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
```
|
|
357
|
+
{:a=>1, :b=>2, :c=>3, :d=>2, :e=>1}
|
|
358
|
+
{:b=>2, :d=>2}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
<a id="org605ad55"></a>
|
|
363
|
+
|
|
364
|
+
### Method `#keys_with_value`
|
|
365
|
+
|
|
366
|
+
Return an `Array` of keys of the `Hash` with a value `==` to the given value or values.
|
|
367
|
+
|
|
368
|
+
```ruby
|
|
369
|
+
h = { a: 1, b: 2, c: 3, d: 2, e: 1 }
|
|
370
|
+
h.keys_with_value(1).inspect
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
```
|
|
374
|
+
"[:a, :e]"
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
```ruby
|
|
378
|
+
h = { a: 1, b: 2, c: 3, d: 2, e: 1 }
|
|
379
|
+
h.keys_with_value(2, 3).inspect
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
```
|
|
383
|
+
"[:b, :d, :c]"
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
<a id="orgdde4b0b"></a>
|
|
388
|
+
|
|
389
|
+
### Method `#remap_keys`
|
|
390
|
+
|
|
391
|
+
This method pre-dates the new `#transform_keys` method now available for `Hash`, but it is kept as an alternative. It takes a `Hash` as an argument that maps existing keys to their replacement in the resulting `Hash`. The original `Hash` is not effected.
|
|
392
|
+
|
|
393
|
+
```ruby
|
|
394
|
+
require_relative './lib/fat_core/hash'
|
|
395
|
+
|
|
396
|
+
h = { a: 1, b: 2, c: 3, d: 2, e: 1 }
|
|
397
|
+
h.remap_keys({:a => :A, :b => :B}).inspect
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
```
|
|
401
|
+
"{:A=>1, :B=>2, :c=>3, :d=>2, :e=>1}"
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
These days, a more systematic job could be done with `#transform_keys`:
|
|
405
|
+
|
|
406
|
+
```ruby
|
|
407
|
+
h = { a: 1, b: 2, c: 3, d: 2, e: 1 }
|
|
408
|
+
h.transform_keys { |k| k.to_s.upcase.to_sym }.inspect
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
```
|
|
412
|
+
"{:A=>1, :B=>2, :C=>3, :D=>2, :E=>1}"
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
<a id="org7603809"></a>
|
|
417
|
+
|
|
418
|
+
### Method `#replace_keys`
|
|
419
|
+
|
|
420
|
+
A wholesale replacement of the existing keys can be done with this method:
|
|
421
|
+
|
|
422
|
+
```ruby
|
|
423
|
+
h = { a: 1, b: 2, c: 3, d: 2, e: 1 }
|
|
424
|
+
h.replace_keys([:z, :y, :x, :w, :v]).inspect
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
```
|
|
428
|
+
"{:z=>1, :y=>2, :x=>3, :w=>2, :v=>1}"
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
<a id="orgadf50ea"></a>
|
|
433
|
+
|
|
434
|
+
### Alias `#merge` to `<<`
|
|
435
|
+
|
|
436
|
+
Finally, `FatCore` adds the "shovel" operator as an alias for `#merge` to provide a pretty way to represent the merger of the right `Hash` into the left `Hash`:
|
|
437
|
+
|
|
438
|
+
```ruby
|
|
439
|
+
{a: 'A', b: 'B', c: 'C'} << {c: 'CC', d: 'DD'} << {d: 'DDD', e: 'EEE'}
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
```
|
|
443
|
+
{:a=>"A", :b=>"B", :c=>"CC", :d=>"DDD", :e=>"EEE"}
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
It groups values into pairs and applies the `#to_h` method to the right-hand argument if it is an `Enumerable`, so it also works if the right-hand argument is an `Array` or `Enumerable`:
|
|
447
|
+
|
|
448
|
+
```ruby
|
|
449
|
+
require 'fileutils'
|
|
450
|
+
|
|
451
|
+
FileUtils.mkdir_p('./tmp')
|
|
452
|
+
ff = File.open('./tmp/junk', 'w')
|
|
453
|
+
ff.write("f\n", "FFFF\n", "g\n", "GGGG\n")
|
|
454
|
+
ff.close
|
|
455
|
+
ff = File.open('./tmp/junk', 'r')
|
|
456
|
+
h = {a: 'A', b: 'B', c: 'C'} <<
|
|
457
|
+
[:c, 'CC', :d, 'DD'] <<
|
|
458
|
+
{d: 'DDD', e: 'EEE'} <<
|
|
459
|
+
ff.readlines.map(&:chomp) <<
|
|
460
|
+
[[:h, 'HHHHH'], [:j, 'JJJJJ']]
|
|
461
|
+
ff.close
|
|
462
|
+
FileUtils.rm_rf('./tmp/junk')
|
|
463
|
+
h
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
```
|
|
467
|
+
{:a=>"A", :b=>"B", :c=>"CC", :d=>"DDD", :e=>"EEE", "f"=>"FFFF", "g"=>"GGGG", :h=>"HHHHH", :j=>"JJJJJ"}
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
<a id="org3918509"></a>
|
|
472
|
+
|
|
473
|
+
## Numeric
|
|
474
|
+
|
|
475
|
+
FatCore::Numeric has methods for inserting grouping commas into a number (`#commas` and `#group`), for converting seconds to HH:MM:SS.dd format (`#secs_to_hms`), for testing for integrality (`#whole?` and `#int_if_whole`), and testing for sign (`#signum`).
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
<a id="org6abf375"></a>
|
|
479
|
+
|
|
480
|
+
### Method `#signum`
|
|
481
|
+
|
|
482
|
+
Return `-1` for negative numbers, `0` for zero, and `+1` for positive numbers. This is sometimes handy.
|
|
483
|
+
|
|
484
|
+
```ruby
|
|
485
|
+
[-55.signum, 0.signum, 55.signum]
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
```
|
|
489
|
+
[-1, 0, 1]
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
<a id="org00c3e90"></a>
|
|
494
|
+
|
|
495
|
+
### Method `#commas(places = nil)`
|
|
496
|
+
|
|
497
|
+
To get s `String` representation of a `Numeric` with grouping commas inserted, `FatCore` provides the `#commas` method:
|
|
498
|
+
|
|
499
|
+
```ruby
|
|
500
|
+
result = []
|
|
501
|
+
result << ['N', 'Places', 'N.commas(places)']
|
|
502
|
+
result << nil
|
|
503
|
+
nums = [3.14159, 2.718281828, 100000, 0.0059, 16236565468798.66877]
|
|
504
|
+
places = [0, 3, 5]
|
|
505
|
+
nums.each do |n|
|
|
506
|
+
places.each do |pl|
|
|
507
|
+
result << [n, pl, n.commas(pl)]
|
|
508
|
+
end
|
|
509
|
+
end
|
|
510
|
+
result
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
```
|
|
514
|
+
| N | Places | N.commas(places) |
|
|
515
|
+
|--------------------+--------+--------------------------|
|
|
516
|
+
| 3.14159 | 0 | 3 |
|
|
517
|
+
| 3.14159 | 3 | 3.142 |
|
|
518
|
+
| 3.14159 | 5 | 3.14159 |
|
|
519
|
+
| 2.718281828 | 0 | 3 |
|
|
520
|
+
| 2.718281828 | 3 | 2.718 |
|
|
521
|
+
| 2.718281828 | 5 | 2.71828 |
|
|
522
|
+
| 100000 | 0 | 100,000 |
|
|
523
|
+
| 100000 | 3 | 100,000.000 |
|
|
524
|
+
| 100000 | 5 | 100,000.00000 |
|
|
525
|
+
| 0.0059 | 0 | 0 |
|
|
526
|
+
| 0.0059 | 3 | 0.006 |
|
|
527
|
+
| 0.0059 | 5 | 0.00590 |
|
|
528
|
+
| 16236565468798.668 | 0 | 16,236,565,468,799 |
|
|
529
|
+
| 16236565468798.668 | 3 | 16,236,565,468,798.668 |
|
|
530
|
+
| 16236565468798.668 | 5 | 16,236,565,468,798.66800 |
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
<a id="orgb844d6f"></a>
|
|
535
|
+
|
|
536
|
+
### Methods `#whole?` and `#int_if_whole`
|
|
537
|
+
|
|
538
|
+
At times it is useful to know if a Float or BigDecimal can be converted to an `Integer` without losing precision.
|
|
539
|
+
|
|
540
|
+
```ruby
|
|
541
|
+
result = []
|
|
542
|
+
result << ['N', '#whole?', '#int_if_whole', 'Classes']
|
|
543
|
+
result << nil
|
|
544
|
+
nums = [3.14159, 3.000000, 100000, 0.0059, 16236565468798.66877]
|
|
545
|
+
nums.each do |n|
|
|
546
|
+
result << [n, n.whole?, n.int_if_whole, "#{n.class} -> #{n.int_if_whole.class}"]
|
|
547
|
+
end
|
|
548
|
+
result
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
```
|
|
552
|
+
| N | #whole? | #int_if_whole | Classes |
|
|
553
|
+
|--------------------+---------+--------------------+--------------------|
|
|
554
|
+
| 3.14159 | false | 3.14159 | Float -> Float |
|
|
555
|
+
| 3.0 | true | 3 | Float -> Integer |
|
|
556
|
+
| 100000 | true | 100000 | Integer -> Integer |
|
|
557
|
+
| 0.0059 | false | 0.0059 | Float -> Float |
|
|
558
|
+
| 16236565468798.668 | false | 16236565468798.668 | Float -> Float |
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
<a id="orgfd1b851"></a>
|
|
563
|
+
|
|
564
|
+
### Method `#secs_to_hms`
|
|
565
|
+
|
|
566
|
+
This method converts a numeric representing a number of seconds or an angle in degrees to a `String` of the form "HH:MM:SS" representing the same quantity in hours (or degrees), minutes, and seconds.
|
|
567
|
+
|
|
568
|
+
```ruby
|
|
569
|
+
result = []
|
|
570
|
+
result << ['N', 'HH:MM:SS']
|
|
571
|
+
result << nil
|
|
572
|
+
nums = [85777.66, 959.66, -1198.33, 0, 3.14159 * 180]
|
|
573
|
+
nums.each do |n|
|
|
574
|
+
result << [n, n.secs_to_hms]
|
|
575
|
+
end
|
|
576
|
+
result
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
```
|
|
580
|
+
| N | HH:MM:SS |
|
|
581
|
+
|-------------------+-------------|
|
|
582
|
+
| 85777.66 | 23:49:37.66 |
|
|
583
|
+
| 959.66 | 00:15:59.66 |
|
|
584
|
+
| -1198.33 | -1:40:01.67 |
|
|
585
|
+
| 0 | 00:00:00 |
|
|
586
|
+
| 565.4861999999999 | 00:09:25.48 |
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
<a id="org7a70260"></a>
|
|
591
|
+
|
|
592
|
+
## Range
|
|
593
|
+
|
|
594
|
+
`FatCore` can also extend the Range class with several useful methods that emphasize coverage of one range by one or more others (`#spanned_by?` and `#gaps`), contiguity of Ranges to one another (`#contiguous?`, `#left_contiguous?`, and `#right_contiguous?`, `#join`), and the testing of overlaps between ranges (`#overlaps?`, `#overlaps_among?`). These are put to good use in the 'fat\_period' (<https://github.com/ddoherty03/fat_period>) gem, which combines fat\_core's extended Range class with its extended Date class to make a useful Period class for date ranges, and you may find fat\_core's extended Range class likewise useful.
|
|
595
|
+
|
|
596
|
+
|
|
597
|
+
<a id="orgdd06e2c"></a>
|
|
598
|
+
|
|
599
|
+
### Methods `#contiguous`, `#left_contiguous`, `#right_contiguous`
|
|
600
|
+
|
|
601
|
+
These methods determine whether the subject `Range` are "contiguous" with another `Range` on the left, right, or either side. The notion of contiguity is different for `Ranges` whose min and max values respond to the `#succ` method: if they do, "contiguity" only requires that the `#succ` of the max value of the left range equal the min value of the right `Range`; otherwise the max value of the left `Range` must equal the min value of the right `Range`.
|
|
602
|
+
|
|
603
|
+
```ruby
|
|
604
|
+
require 'date'
|
|
605
|
+
|
|
606
|
+
result = []
|
|
607
|
+
result << ["Self", "Other", "Contiguous?", "Right?", "Left?"]
|
|
608
|
+
result << nil
|
|
609
|
+
pairs = [
|
|
610
|
+
[(0..10), (11..12)],
|
|
611
|
+
[(11..20), (0..10)],
|
|
612
|
+
[(0..10), (15..20)],
|
|
613
|
+
[(3.145..12.3), (0.5..3.145)],
|
|
614
|
+
[(3.146..12.3), (0.5..3.145)],
|
|
615
|
+
[('a'..'q'), ('r'..'z')],
|
|
616
|
+
[('a'..'q'), ('s'..'z')],
|
|
617
|
+
[(Date.parse('1963-11-22')..Date.parse('1964-11-03')), (Date.parse('1964-11-04')..Date.today)],
|
|
618
|
+
[(Date.parse('1963-11-22')..Date.parse('1964-11-03')), (Date.parse('1964-11-28')..Date.today)]
|
|
619
|
+
]
|
|
620
|
+
pairs.each do |r1, r2|
|
|
621
|
+
result << [r1.to_s, r2.to_s, r1.contiguous?(r2), r1.right_contiguous?(r2), r1.left_contiguous?(r2)]
|
|
622
|
+
end
|
|
623
|
+
result
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
```
|
|
627
|
+
| Self | Other | Contiguous? | Right? | Left? |
|
|
628
|
+
|------------------------+------------------------+-------------+--------+-------|
|
|
629
|
+
| 0..10 | 11..12 | true | true | false |
|
|
630
|
+
| 11..20 | 0..10 | true | false | true |
|
|
631
|
+
| 0..10 | 15..20 | false | false | false |
|
|
632
|
+
| 3.145..12.3 | 0.5..3.145 | true | false | true |
|
|
633
|
+
| 3.146..12.3 | 0.5..3.145 | false | false | false |
|
|
634
|
+
| a..q | r..z | true | true | false |
|
|
635
|
+
| a..q | s..z | false | false | false |
|
|
636
|
+
| 1963-11-22..1964-11-03 | 1964-11-04..2026-05-29 | true | true | false |
|
|
637
|
+
| 1963-11-22..1964-11-03 | 1964-11-28..2026-05-29 | false | false | false |
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
<a id="org28a7d95"></a>
|
|
642
|
+
|
|
643
|
+
### Method `#join(other)`
|
|
644
|
+
|
|
645
|
+
If `self` is contiguous with `other`, return a new `Range` that splices the two `Range~s into one ~Range`.
|
|
646
|
+
|
|
647
|
+
```ruby
|
|
648
|
+
require 'date'
|
|
649
|
+
|
|
650
|
+
result = []
|
|
651
|
+
result << ["Self", "Other", "Contiguous?", "Joined"]
|
|
652
|
+
result << nil
|
|
653
|
+
pairs = [
|
|
654
|
+
[(0..10), (11..12)],
|
|
655
|
+
[(11..20), (0..10)],
|
|
656
|
+
[(0..10), (15..20)],
|
|
657
|
+
[(3.145..12.3), (0.5..3.145)],
|
|
658
|
+
[(3.146..12.3), (0.5..3.145)],
|
|
659
|
+
[('a'..'q'), ('r'..'z')],
|
|
660
|
+
[('a'..'q'), ('s'..'z')],
|
|
661
|
+
[(Date.parse('1963-11-22')..Date.parse('1964-11-03')), (Date.parse('1964-11-04')..Date.today)],
|
|
662
|
+
[(Date.parse('1963-11-22')..Date.parse('1964-11-03')), (Date.parse('1964-11-28')..Date.today)]
|
|
663
|
+
]
|
|
664
|
+
pairs.each do |r1, r2|
|
|
665
|
+
result << [r1.to_s, r2.to_s, r1.contiguous?(r2), "#{r1.join(r2)}"]
|
|
666
|
+
end
|
|
667
|
+
result
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
```
|
|
671
|
+
| Self | Other | Contiguous? | Joined |
|
|
672
|
+
|------------------------+------------------------+-------------+------------------------|
|
|
673
|
+
| 0..10 | 11..12 | true | 0..12 |
|
|
674
|
+
| 11..20 | 0..10 | true | 0..20 |
|
|
675
|
+
| 0..10 | 15..20 | false | |
|
|
676
|
+
| 3.145..12.3 | 0.5..3.145 | true | 0.5..12.3 |
|
|
677
|
+
| 3.146..12.3 | 0.5..3.145 | false | |
|
|
678
|
+
| a..q | r..z | true | a..z |
|
|
679
|
+
| a..q | s..z | false | |
|
|
680
|
+
| 1963-11-22..1964-11-03 | 1964-11-04..2026-05-29 | true | 1963-11-22..2026-05-29 |
|
|
681
|
+
| 1963-11-22..1964-11-03 | 1964-11-28..2026-05-29 | false | |
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
|
|
685
|
+
<a id="org5d367a6"></a>
|
|
686
|
+
|
|
687
|
+
### Method `#spanned_by?(others)`
|
|
688
|
+
|
|
689
|
+
A set of `Ranges` "spans" a given `Range` if the set is contiguous and fully covers the given `Range` with no overlaps and no gaps. A set that over-covers the given `Range` is still considered to span it, even though it is wider than the given `Range`. In other words, a set spans the given `Range` if the set can be joined and the given `Range` is within the joined `Range`.
|
|
690
|
+
|
|
691
|
+
```ruby
|
|
692
|
+
require 'date'
|
|
693
|
+
|
|
694
|
+
result = []
|
|
695
|
+
result << ["Self", "Others", "Spanned By?"]
|
|
696
|
+
result << nil
|
|
697
|
+
pairs = [
|
|
698
|
+
[(0..10), [(-1..5), (6..10)]],
|
|
699
|
+
[(1..20), [(0..10), (11..20)]],
|
|
700
|
+
[(1..20), [(0..10), (10..20)]],
|
|
701
|
+
[(3.145..12.3), [(0.5..3.45), (3.45..10.5), (10.5..13.5)]],
|
|
702
|
+
[(3.145..12.3), [(0.5..3.45), (3.45..10.5), (10.6..13.5)]],
|
|
703
|
+
[('a'..'z'), [('a'..'g'), ('h'..'s'), ('t'..'z')]],
|
|
704
|
+
[('a'..'z'), [('a'..'g'), ('j'..'s'), ('t'..'z')]],
|
|
705
|
+
]
|
|
706
|
+
pairs.each do |r, others|
|
|
707
|
+
result << ["#{r}", "#{others}", r.spanned_by?(others)]
|
|
708
|
+
end
|
|
709
|
+
result
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
```
|
|
713
|
+
| Self | Others | Spanned By? |
|
|
714
|
+
|-------------+-------------------------------------+-------------|
|
|
715
|
+
| 0..10 | [-1..5, 6..10] | true |
|
|
716
|
+
| 1..20 | [0..10, 11..20] | true |
|
|
717
|
+
| 1..20 | [0..10, 10..20] | false |
|
|
718
|
+
| 3.145..12.3 | [0.5..3.45, 3.45..10.5, 10.5..13.5] | true |
|
|
719
|
+
| 3.145..12.3 | [0.5..3.45, 3.45..10.5, 10.6..13.5] | false |
|
|
720
|
+
| a..z | ["a".."g", "h".."s", "t".."z"] | true |
|
|
721
|
+
| a..z | ["a".."g", "j".."s", "t".."z"] | false |
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
<a id="orga33fd47"></a>
|
|
726
|
+
|
|
727
|
+
### Methods `#gaps(others)`, `#overlaps(others)`
|
|
728
|
+
|
|
729
|
+
When the set of other `Ranges` does not span the given `Range`, these methods return an set of `Ranges` that represent the portions of the given `Range` no covered by the `others`, the "gaps", or the points within the given `Range` where the `others` overlap one another and thus are not contiguous.
|
|
730
|
+
|
|
731
|
+
```ruby
|
|
732
|
+
require 'date'
|
|
733
|
+
|
|
734
|
+
result = []
|
|
735
|
+
result << ["Self", "Others", "Spanned By?", "Gaps", "Overlaps"]
|
|
736
|
+
result << nil
|
|
737
|
+
pairs = [
|
|
738
|
+
[(0..10), [(-1..5), (6..10)]],
|
|
739
|
+
[(1..20), [(0..10), (11..20)]],
|
|
740
|
+
[(1..20), [(0..15), (11..20)]],
|
|
741
|
+
[(1..20), [(0..10), (10..20)]],
|
|
742
|
+
[(3.145..12.3), [(0.5..3.45), (3.45..10.5), (10.5..13.5)]],
|
|
743
|
+
[(3.145..12.3), [(0.5..3.45), (3.45..10.5), (10.6..13.5)]],
|
|
744
|
+
[('a'..'z'), [('a'..'g'), ('h'..'s'), ('t'..'z')]],
|
|
745
|
+
[('a'..'z'), [('a'..'g'), ('j'..'s'), ('t'..'z')]],
|
|
746
|
+
]
|
|
747
|
+
pairs.each do |r, others|
|
|
748
|
+
result << ["#{r}", "#{others}", r.spanned_by?(others), "#{r.gaps(others)}", "#{r.overlaps(others)}"]
|
|
749
|
+
end
|
|
750
|
+
result
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
```
|
|
754
|
+
| Self | Others | Spanned By? | Gaps | Overlaps |
|
|
755
|
+
|-------------+-------------------------------------+-------------+--------------+----------|
|
|
756
|
+
| 0..10 | [-1..5, 6..10] | true | [] | [] |
|
|
757
|
+
| 1..20 | [0..10, 11..20] | true | [] | [] |
|
|
758
|
+
| 1..20 | [0..15, 11..20] | false | [] | [11..15] |
|
|
759
|
+
| 1..20 | [0..10, 10..20] | false | [] | [] |
|
|
760
|
+
| 3.145..12.3 | [0.5..3.45, 3.45..10.5, 10.5..13.5] | true | [] | [] |
|
|
761
|
+
| 3.145..12.3 | [0.5..3.45, 3.45..10.5, 10.6..13.5] | false | [10.5..10.6] | [] |
|
|
762
|
+
| a..z | ["a".."g", "h".."s", "t".."z"] | true | [] | [] |
|
|
763
|
+
| a..z | ["a".."g", "j".."s", "t".."z"] | false | ["h".."i"] | [] |
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
<a id="orgbd1bd5e"></a>
|
|
768
|
+
|
|
769
|
+
## String
|
|
770
|
+
|
|
771
|
+
FatCore::String has methods for performing matching of one string with another (`#matches_with`, `#fuzzy_match`), for converting a string to title-case as might by used in the title of a book (`#entitle`), for converting a String into a useable Symbol (`#as_sym`) and vice-versa (`#as_str` also `Symbol#as_str`), for wrapping with an optional hanging indent (`#wrap`), cleaning up errant spaces (`#clean`), and computing the Damerau-Levenshtein distance between strings (`#distance`). And several others.
|
|
772
|
+
|
|
773
|
+
|
|
774
|
+
<a id="org63111cb"></a>
|
|
775
|
+
|
|
776
|
+
### Method `#fuzzy_match`
|
|
777
|
+
|
|
778
|
+
The `#fuzzy_match` method determines whether the subject string matches the given "matcher" string, which provides a simple syntax that allows a limited kind of pattern matching. If there is a match, it returns the matched portion of self, minus punctuation characters, if self matches the string, and returns nil otherwise.
|
|
779
|
+
|
|
780
|
+
What makes this handy is that a user trying to match by memory can be loose about case, punctuation, and spaces, and still find desired matches. In the matcher both the space and colon ':' have special meaning as shown below.
|
|
781
|
+
|
|
782
|
+
`#fuzzy_match(matcher)` uses the following rules for matching:
|
|
783
|
+
|
|
784
|
+
1. Remove leading and trailing whitespace in the subject and the matcher and collapse its internal whitespace to a single space,
|
|
785
|
+
2. In the subject string replace periods and commas with a space (so they still act as word separators) but remove apostrophes, and asterisks so the user need not remember whether they were used when forming the matcher.
|
|
786
|
+
3. In the matcher, make any period, comma, asterisk, or apostrophe optional for the same reason.
|
|
787
|
+
4. Treat internal ':stuff' or ' :stuff' in the matcher as the equivalent of *\bstuff.\** in a regular expression, that is, match any word starting with stuff in self,
|
|
788
|
+
5. Treat internal 'stuff: ' in the matcher as the equivalent of *.\*stuff\b* in a regular expression, that is, match any word ending with stuff in self,
|
|
789
|
+
6. A colon with no spaces around it is treated as belonging to the following word, requiring it to start with it, so 'some:stuff' requires 'some' anywhere followed by a word beginning with 'stuff', i.e., /some.\*\bstuff/i,
|
|
790
|
+
7. Treat leading ':' in the matcher as anchoring the match to the beginning of the target string,
|
|
791
|
+
8. Treat ending ':' in the matcher as anchoring the match to the end of the target string,
|
|
792
|
+
9. Require each component to match some part of self, and
|
|
793
|
+
|
|
794
|
+
```ruby
|
|
795
|
+
result = []
|
|
796
|
+
result << ['Self', 'Matcher', 'Match']
|
|
797
|
+
result << nil
|
|
798
|
+
subj = "St. Luke's Hospital"
|
|
799
|
+
matchers = ['st lukes', 'st. luke\'s', 'luk:hosp', 'st:spital', 'uk spital', 'st:laks', ':lukes', 's lukes', 'lukes:hospital']
|
|
800
|
+
matchers.each do |m|
|
|
801
|
+
result << [subj, m, subj.fuzzy_match(m)]
|
|
802
|
+
end
|
|
803
|
+
result
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
```
|
|
807
|
+
| Self | Matcher | Match |
|
|
808
|
+
|---------------------+----------------+----------------|
|
|
809
|
+
| St. Luke's Hospital | st lukes | St Lukes |
|
|
810
|
+
| St. Luke's Hospital | st. luke's | St Lukes |
|
|
811
|
+
| St. Luke's Hospital | luk:hosp | Lukes Hosp |
|
|
812
|
+
| St. Luke's Hospital | st:spital | nil |
|
|
813
|
+
| St. Luke's Hospital | uk spital | ukes Hospital |
|
|
814
|
+
| St. Luke's Hospital | st:laks | nil |
|
|
815
|
+
| St. Luke's Hospital | :lukes | nil |
|
|
816
|
+
| St. Luke's Hospital | s lukes | St Lukes |
|
|
817
|
+
| St. Luke's Hospital | lukes:hospital | Lukes Hospital |
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
|
|
821
|
+
<a id="orgdae93bf"></a>
|
|
822
|
+
|
|
823
|
+
### Method `#matches_with`
|
|
824
|
+
|
|
825
|
+
The `#matches_with(matcher)` method allows the use of either a regular expression or fuzzy matching as described above depending on whether the matcher is enclosed in '/' characters. It also returns the matched portion of `self` or nil if there is no match. Even when a regex is given, the match is case insensitive by default and commas, apostrophes, and periods are removed from the subject string before matching.
|
|
826
|
+
|
|
827
|
+
```ruby
|
|
828
|
+
result = []
|
|
829
|
+
result << ['Self', 'Matcher', 'Match']
|
|
830
|
+
result << nil
|
|
831
|
+
subj = "St. Luke's Hospital"
|
|
832
|
+
matchers = ['st lukes', '/luk.*hosp/', 'st:spital', '/u.*s\b/', 'st:laks', ':lukes', 's lukes', '/lukes hospital\z/']
|
|
833
|
+
matchers.each do |m|
|
|
834
|
+
result << [subj, m, subj.matches_with(m)]
|
|
835
|
+
end
|
|
836
|
+
result
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
```
|
|
840
|
+
| Self | Matcher | Match |
|
|
841
|
+
|---------------------+--------------------+-------------|
|
|
842
|
+
| St. Luke's Hospital | st lukes | St Lukes |
|
|
843
|
+
| St. Luke's Hospital | /luk.*hosp/ | Luke's Hosp |
|
|
844
|
+
| St. Luke's Hospital | st:spital | nil |
|
|
845
|
+
| St. Luke's Hospital | /u.*s\b/ | uke's |
|
|
846
|
+
| St. Luke's Hospital | st:laks | nil |
|
|
847
|
+
| St. Luke's Hospital | :lukes | nil |
|
|
848
|
+
| St. Luke's Hospital | s lukes | St Lukes |
|
|
849
|
+
| St. Luke's Hospital | /lukes hospital\z/ | nil |
|
|
850
|
+
```
|
|
851
|
+
|
|
852
|
+
|
|
853
|
+
<a id="org1a5d1e4"></a>
|
|
854
|
+
|
|
855
|
+
### Method `#entitle`
|
|
856
|
+
|
|
857
|
+
For a string meant to serve as the title of a book, song, or other item, there are certain rules in English as to which words should be capitalized and which should be put in lower case. "PROFILES IN courage" should be rendered "Profiles in Courage" for example. The preposition "in" is typically not capitalized unless it starts the title: "in the HEAT OF THE NIght" should be something like "In the Heat of the Night".
|
|
858
|
+
|
|
859
|
+
```ruby
|
|
860
|
+
result = []
|
|
861
|
+
result << ['Self', 'Entitled']
|
|
862
|
+
result << nil
|
|
863
|
+
titles = ['PROFILES IN courage', 'in the HEAT OF THE NIght', 'a day in the life', 'FROM HERE TO ETERNITY',
|
|
864
|
+
'lucy in the sky with diamonds']
|
|
865
|
+
titles.each do |t|
|
|
866
|
+
result << [t, t.entitle]
|
|
867
|
+
end
|
|
868
|
+
result
|
|
869
|
+
```
|
|
870
|
+
|
|
871
|
+
```
|
|
872
|
+
| Self | Entitled |
|
|
873
|
+
|-------------------------------+-------------------------------|
|
|
874
|
+
| PROFILES IN courage | Profiles in Courage |
|
|
875
|
+
| in the HEAT OF THE NIght | In the Heat of the Night |
|
|
876
|
+
| a day in the life | A Day in the Life |
|
|
877
|
+
| FROM HERE TO ETERNITY | From Here to Eternity |
|
|
878
|
+
| lucy in the sky with diamonds | Lucy in the Sky With Diamonds |
|
|
879
|
+
```
|
|
880
|
+
|
|
881
|
+
|
|
882
|
+
<a id="orgd671ee5"></a>
|
|
883
|
+
|
|
884
|
+
### Method `#distance`
|
|
885
|
+
|
|
886
|
+
`FatCore` provides `distance` as a simple wrapper around the Damerau-Levenshtein distance function in `damerau-levenshtein` gem, using a block size of 1 and a max distance of 10.
|
|
887
|
+
|
|
888
|
+
```ruby
|
|
889
|
+
result = []
|
|
890
|
+
result << ['Word1', 'Word2', 'Distance']
|
|
891
|
+
result << nil
|
|
892
|
+
pairs = [['Shelf', 'Shell'], ['Shelf', 'Shall'], ['Doherty', 'Daughtery'], ['Doherty', 'Dorrit'], ['Smith', 'Jones']]
|
|
893
|
+
pairs.each do |w1, w2|
|
|
894
|
+
result << [w1, w2, w1.distance(w2)]
|
|
895
|
+
end
|
|
896
|
+
result
|
|
897
|
+
```
|
|
898
|
+
|
|
899
|
+
```
|
|
900
|
+
| Word1 | Word2 | Distance |
|
|
901
|
+
|---------+-----------+----------|
|
|
902
|
+
| Shelf | Shell | 1 |
|
|
903
|
+
| Shelf | Shall | 2 |
|
|
904
|
+
| Doherty | Daughtery | 5 |
|
|
905
|
+
| Doherty | Dorrit | 4 |
|
|
906
|
+
| Smith | Jones | 5 |
|
|
907
|
+
```
|
|
908
|
+
|
|
909
|
+
|
|
910
|
+
<a id="orgfdd51bd"></a>
|
|
911
|
+
|
|
912
|
+
### Method `#commas(places)`
|
|
913
|
+
|
|
914
|
+
When presenting numbers, it is common to want to add grouping digits to make the numbers more readable. The `commas(places)` method does this be converting the number into a Float, rounding to places digits, then converting back to a `String` with grouping commas inserted.
|
|
915
|
+
|
|
916
|
+
```ruby
|
|
917
|
+
result = []
|
|
918
|
+
result << ['N', 'Places', 'With Commas']
|
|
919
|
+
result << nil
|
|
920
|
+
nums_places = [["798964655.66541325", 3], ["798964655.66541325", 0], ["798964655.66541325", 5], ["3.14159", 3],
|
|
921
|
+
["3.14159e6", 3], ["-3.14159e4", 2], ["+3.14159e3", 2]]
|
|
922
|
+
nums_places.each do |n, p|
|
|
923
|
+
result << [n, p, n.commas(p)]
|
|
924
|
+
end
|
|
925
|
+
result
|
|
926
|
+
```
|
|
927
|
+
|
|
928
|
+
```
|
|
929
|
+
| N | Places | With Commas |
|
|
930
|
+
|--------------------+--------+-------------------|
|
|
931
|
+
| 798964655.66541325 | 3 | 798,964,655.665 |
|
|
932
|
+
| 798964655.66541325 | 0 | 798,964,656 |
|
|
933
|
+
| 798964655.66541325 | 5 | 798,964,655.66541 |
|
|
934
|
+
| 3.14159 | 3 | 3.142 |
|
|
935
|
+
| 3.14159e6 | 3 | 3,141,590.000 |
|
|
936
|
+
| -3.14159e4 | 2 | -31,415.90 |
|
|
937
|
+
| +3.14159e3 | 2 | 3,141.59 |
|
|
938
|
+
```
|
|
939
|
+
|
|
940
|
+
|
|
941
|
+
<a id="org826950e"></a>
|
|
942
|
+
|
|
943
|
+
### Method `#wrap(width, hang)`
|
|
944
|
+
|
|
945
|
+
This method wraps the string to a given width with an optional hanging indent for lines after the first.
|
|
946
|
+
|
|
947
|
+
```ruby
|
|
948
|
+
getty = <<~EOS
|
|
949
|
+
Four score and seven years ago our fathers brought forth on this continent,
|
|
950
|
+
a new nation, conceived in Liberty, and dedicated to the proposition that
|
|
951
|
+
all men are created equal.
|
|
952
|
+
|
|
953
|
+
Now we are engaged in a great civil war, testing whether that nation, or any
|
|
954
|
+
nation so conceived and so dedicated, can long endure. We are met on a
|
|
955
|
+
great battle-field of that war. We have come to dedicate a portion of that
|
|
956
|
+
field, as a final resting place for those who here gave their lives that
|
|
957
|
+
that nation might live. It is altogether fitting and proper that we should
|
|
958
|
+
do this.
|
|
959
|
+
|
|
960
|
+
But, in a larger sense, we can not dedicate---we can not consecrate---we can
|
|
961
|
+
not hallow---this ground. The brave men, living and dead, who struggled
|
|
962
|
+
here, have consecrated it, far above our poor power to add or detract. The
|
|
963
|
+
world will little note, nor long remember what we say here, but it can never
|
|
964
|
+
forget what they did here. It is for us the living, rather, to be dedicated
|
|
965
|
+
here to the unfinished work which they who fought here have thus far so
|
|
966
|
+
nobly advanced. It is rather for us to be here dedicated to the great task
|
|
967
|
+
remaining before us---that from these honored dead we take increased
|
|
968
|
+
devotion to that cause for which they gave the last full measure of
|
|
969
|
+
devotion---that we here highly resolve that these dead shall not have died
|
|
970
|
+
in vain---that this nation, under God, shall have a new birth of
|
|
971
|
+
freedom---and that government of the people, by the people, for the people,
|
|
972
|
+
shall not perish from the earth.
|
|
973
|
+
EOS
|
|
974
|
+
getty.wrap(110, 3)
|
|
975
|
+
```
|
|
976
|
+
|
|
977
|
+
```
|
|
978
|
+
Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived
|
|
979
|
+
in Liberty, and dedicated to the proposition that all men are created equal. Now we are engaged
|
|
980
|
+
in a great civil war, testing whether that nation, or any nation so conceived and so dedicated,
|
|
981
|
+
can long endure. We are met on a great battle-field of that war. We have come to dedicate
|
|
982
|
+
a portion of that field, as a final resting place for those who here gave their lives that
|
|
983
|
+
that nation might live. It is altogether fitting and proper that we should do this. But, in
|
|
984
|
+
a larger sense, we can not dedicate---we can not consecrate---we can not hallow---this ground.
|
|
985
|
+
The brave men, living and dead, who struggled here, have consecrated it, far above our poor
|
|
986
|
+
power to add or detract. The world will little note, nor long remember what we say here, but
|
|
987
|
+
it can never forget what they did here. It is for us the living, rather, to be dedicated here
|
|
988
|
+
to the unfinished work which they who fought here have thus far so nobly advanced. It is rather
|
|
989
|
+
for us to be here dedicated to the great task remaining before us---that from these honored
|
|
990
|
+
dead we take increased devotion to that cause for which they gave the last full measure of
|
|
991
|
+
devotion---that we here highly resolve that these dead shall not have died in vain---that this
|
|
992
|
+
nation, under God, shall have a new birth of freedom---and that government of the people, by
|
|
993
|
+
the people, for the people, shall not perish from the earth.
|
|
994
|
+
```
|
|
995
|
+
|
|
996
|
+
```ruby
|
|
997
|
+
getty.wrap(40, 2)
|
|
998
|
+
```
|
|
999
|
+
|
|
1000
|
+
```
|
|
1001
|
+
Four score and seven years ago our
|
|
1002
|
+
fathers brought forth on this continent,
|
|
1003
|
+
a new nation, conceived in Liberty,
|
|
1004
|
+
and dedicated to the proposition that
|
|
1005
|
+
all men are created equal. Now we
|
|
1006
|
+
are engaged in a great civil war,
|
|
1007
|
+
testing whether that nation, or any
|
|
1008
|
+
nation so conceived and so dedicated,
|
|
1009
|
+
can long endure. We are met on a
|
|
1010
|
+
great battle-field of that war. We
|
|
1011
|
+
have come to dedicate a portion of
|
|
1012
|
+
that field, as a final resting place
|
|
1013
|
+
for those who here gave their lives
|
|
1014
|
+
that that nation might live. It is
|
|
1015
|
+
altogether fitting and proper that
|
|
1016
|
+
we should do this. But, in a larger
|
|
1017
|
+
sense, we can not dedicate---we can
|
|
1018
|
+
not consecrate---we can not hallow---this
|
|
1019
|
+
ground. The brave men, living and
|
|
1020
|
+
dead, who struggled here, have consecrated
|
|
1021
|
+
it, far above our poor power to
|
|
1022
|
+
add or detract. The world will little
|
|
1023
|
+
note, nor long remember what we say
|
|
1024
|
+
here, but it can never forget what
|
|
1025
|
+
they did here. It is for us the
|
|
1026
|
+
living, rather, to be dedicated here
|
|
1027
|
+
to the unfinished work which they
|
|
1028
|
+
who fought here have thus far so
|
|
1029
|
+
nobly advanced. It is rather for
|
|
1030
|
+
us to be here dedicated to the great
|
|
1031
|
+
task remaining before us---that from
|
|
1032
|
+
these honored dead we take increased
|
|
1033
|
+
devotion to that cause for which
|
|
1034
|
+
they gave the last full measure of
|
|
1035
|
+
devotion---that we here highly resolve
|
|
1036
|
+
that these dead shall not have died
|
|
1037
|
+
in vain---that this nation, under
|
|
1038
|
+
God, shall have a new birth of freedom---and
|
|
1039
|
+
that government of the people, by
|
|
1040
|
+
the people, for the people, shall
|
|
1041
|
+
not perish from the earth.
|
|
1042
|
+
```
|
|
1043
|
+
|
|
1044
|
+
|
|
1045
|
+
<a id="orgc017d90"></a>
|
|
1046
|
+
|
|
1047
|
+
### Method `#as_sym`
|
|
1048
|
+
|
|
1049
|
+
Convert a `String` to a `Symbol` by converting all letters to lower-case, replacing hyphens and white space with a single underscore, and removing all non-alphanumeric characters:
|
|
1050
|
+
|
|
1051
|
+
```ruby
|
|
1052
|
+
" Hello-to-the World!!!".as_sym
|
|
1053
|
+
```
|
|
1054
|
+
|
|
1055
|
+
```
|
|
1056
|
+
:hello_to_the_world
|
|
1057
|
+
```
|
|
1058
|
+
|
|
1059
|
+
|
|
1060
|
+
<a id="org3459d99"></a>
|
|
1061
|
+
|
|
1062
|
+
### Method `gut`
|
|
1063
|
+
|
|
1064
|
+
Very often one wants to truncate a string to a given size, but it is often the case that the most important parts of a string are at the beginning and the end. The `#gut(size)` method returns a sting of length `size` by removing content from the middle of the string and leaving as much as possible at the two ends.
|
|
1065
|
+
|
|
1066
|
+
```ruby
|
|
1067
|
+
result = []
|
|
1068
|
+
result << ['Self', 'Gutted']
|
|
1069
|
+
result << nil
|
|
1070
|
+
strings = ["/usr/bin/fallacious", "Class A Common Stock", 'PROFILES IN courage', 'in the HEAT OF THE NIght', 'a day in the life', 'FROM HERE TO ETERNITY',
|
|
1071
|
+
'lucy in the sky with diamonds']
|
|
1072
|
+
strings.each do |t|
|
|
1073
|
+
result << [t, t.gut(15)]
|
|
1074
|
+
end
|
|
1075
|
+
result
|
|
1076
|
+
```
|
|
1077
|
+
|
|
1078
|
+
```
|
|
1079
|
+
| Self | Gutted |
|
|
1080
|
+
|-------------------------------+-----------------|
|
|
1081
|
+
| /usr/bin/fallacious | /usr/bi~lacious |
|
|
1082
|
+
| Class A Common Stock | Class A~n Stock |
|
|
1083
|
+
| PROFILES IN courage | PROFILE~courage |
|
|
1084
|
+
| in the HEAT OF THE NIght | in the ~E NIght |
|
|
1085
|
+
| a day in the life | a day i~he life |
|
|
1086
|
+
| FROM HERE TO ETERNITY | FROM HE~TERNITY |
|
|
1087
|
+
| lucy in the sky with diamonds | lucy in~iamonds |
|
|
1088
|
+
```
|
|
1089
|
+
|
|
1090
|
+
By default, the deleted middle part is replace with the tilde character, but with the ellipsis parameter, you can make it whatever you want:
|
|
1091
|
+
|
|
1092
|
+
```ruby
|
|
1093
|
+
'Class A Common Stock'.gut(15, ellipsis: '...')
|
|
1094
|
+
```
|
|
1095
|
+
|
|
1096
|
+
```
|
|
1097
|
+
Class ... Stock
|
|
1098
|
+
```
|
|
1099
|
+
|
|
1100
|
+
Including, nothing at all:
|
|
1101
|
+
|
|
1102
|
+
```ruby
|
|
1103
|
+
'Class A Common Stock'.gut(15, ellipsis: '')
|
|
1104
|
+
```
|
|
1105
|
+
|
|
1106
|
+
```
|
|
1107
|
+
Class A n Stock
|
|
1108
|
+
```
|
|
1109
|
+
|
|
1110
|
+
And, you can optionally squeeze out spaces or other characters with the
|
|
1111
|
+
|
|
1112
|
+
```ruby
|
|
1113
|
+
'Class A Common Stock'.gut(16, ellipsis: '', squeeze: ' ')
|
|
1114
|
+
```
|
|
1115
|
+
|
|
1116
|
+
```
|
|
1117
|
+
ClassAComonStock
|
|
1118
|
+
```
|
|
1119
|
+
|
|
1120
|
+
|
|
1121
|
+
<a id="org2241c53"></a>
|
|
1122
|
+
|
|
1123
|
+
## Symbol
|
|
1124
|
+
|
|
1125
|
+
|
|
1126
|
+
<a id="orgf2478cc"></a>
|
|
1127
|
+
|
|
1128
|
+
### Method `#as_str`
|
|
1129
|
+
|
|
1130
|
+
A quasi-inverse of `String#as_sym`, convert a `Symbol` into a `String` by converting '<span class="underline">' to a hyphen, white-space into '</span>', and eliminate any non-alphanumeric characters.
|
|
1131
|
+
|
|
1132
|
+
```ruby
|
|
1133
|
+
:hello_to_the_world.as_str
|
|
1134
|
+
```
|
|
1135
|
+
|
|
1136
|
+
```
|
|
1137
|
+
hello-to-the-world
|
|
1138
|
+
```
|
|
1139
|
+
|
|
1140
|
+
|
|
1141
|
+
<a id="org5620bc3"></a>
|
|
1142
|
+
|
|
1143
|
+
## TeX Quoting
|
|
1144
|
+
|
|
1145
|
+
The extensions for `String`, `Numeric`, `Range`, `Symbol`, and `NilClass` provide a `#tex_quote` method for quoting the string version of an object so as to allow its inclusion in a TeX document while quoting characters such as '\_', $' or '%' that have a special meaning for TeX. At the same time it deploys TeX notation when special notation is available, for example, a `Rational` is rendered as a fraction.
|
|
1146
|
+
|
|
1147
|
+
```ruby
|
|
1148
|
+
require 'date'
|
|
1149
|
+
|
|
1150
|
+
result = []
|
|
1151
|
+
result << ['Class', 'Example', '#tex_quote']
|
|
1152
|
+
result << nil
|
|
1153
|
+
examples = [
|
|
1154
|
+
"Save $100 or 14% on this Friday_Black",
|
|
1155
|
+
58743.44,
|
|
1156
|
+
Float::INFINITY,
|
|
1157
|
+
Math::PI,
|
|
1158
|
+
Complex(5, 3),
|
|
1159
|
+
Complex(5.0, 3.0),
|
|
1160
|
+
Rational(5, 3),
|
|
1161
|
+
Rational(8.0, 17.0),
|
|
1162
|
+
(Date.parse('2020-09-22')..Date.today),
|
|
1163
|
+
(Math::E..Math::PI),
|
|
1164
|
+
:four_score_and_7_years,
|
|
1165
|
+
nil
|
|
1166
|
+
]
|
|
1167
|
+
examples.each do |ex|
|
|
1168
|
+
result << [ex.class, ex.to_s, ex.tex_quote.inspect]
|
|
1169
|
+
end
|
|
1170
|
+
result
|
|
1171
|
+
```
|
|
1172
|
+
|
|
1173
|
+
```
|
|
1174
|
+
| Class | Example | #tex_quote |
|
|
1175
|
+
|----------+---------------------------------------+-----------------------------------------------|
|
|
1176
|
+
| String | Save $100 or 14% on this Friday_Black | "Save \\$100 or 14\\% on this Friday\\_Black" |
|
|
1177
|
+
| Float | 58743.44 | "58743.44" |
|
|
1178
|
+
| Float | Infinity | "$\\infty$" |
|
|
1179
|
+
| Float | 3.141592653589793 | "$\\pi$" |
|
|
1180
|
+
| Complex | 5+3i | "$5+3i$" |
|
|
1181
|
+
| Complex | 5.0+3.0i | "$5+3i$" |
|
|
1182
|
+
| Rational | 5/3 | "$\\frac{5}{3}$" |
|
|
1183
|
+
| Rational | 8/17 | "$\\frac{8}{17}$" |
|
|
1184
|
+
| Range | 2020-09-22..2026-05-29 | "(2020-09-22..2026-05-29)" |
|
|
1185
|
+
| Range | 2.718281828459045..3.141592653589793 | "($e$..$\\pi$)" |
|
|
1186
|
+
| Symbol | four_score_and_7_years | "four\\_score\\_and\\_7\\_years" |
|
|
1187
|
+
| NilClass | | "" |
|
|
1188
|
+
```
|
|
1189
|
+
|
|
1190
|
+
|
|
1191
|
+
<a id="orgfe2e72b"></a>
|
|
1192
|
+
|
|
1193
|
+
# Contributing
|
|
1194
|
+
|
|
1195
|
+
1. Fork it (<http://github.com/ddoherty03/fat_core/fork> )
|
|
1196
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
1197
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
1198
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
1199
|
+
5. Create new Pull Request
|