fat_core 5.6.1 → 7.0.1

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.
data/README.org CHANGED
@@ -1,17 +1,108 @@
1
- [[https://travis-ci.org/ddoherty03/fat_core.svg?branch=master]]
1
+ #+TITLE: FatCore Guide
2
+ #+OPTIONS: toc:5
3
+ #+PROPERTY: header-args:ruby :colnames no :hlines yes :exports both :wrap example :ruby ruby
4
+ #+PROPERTY: header-args:sh :exports code
5
+
6
+ [[https://github.com/ddoherty03/fat_core/actions/workflows/ruby.yml][https://github.com/ddoherty03/fat_core/actions/workflows/ruby.yml/badge.svg?branch=master]]
7
+
8
+ * README Setup Do First for Code Blocks :noexport:
9
+ Run this block before all others to ensure that we are reading the libraries
10
+ from the source directory.
11
+
12
+ #+begin_src ruby :results output
13
+ puts "Current directory: #{Dir.pwd}"
14
+ puts "Ruby LOADPATH:"
15
+ $:.unshift("./lib") unless $:[0] == './lib'
16
+ $:[0..10].each { |d| puts d }
17
+ puts "..."
18
+ require_relative 'lib/fat_core/all' # => true
19
+ #+end_src
20
+
21
+ #+RESULTS:
22
+ #+begin_example
23
+ Current directory: /home/ded/src/fat_core
24
+ Ruby LOADPATH:
25
+ ./lib
26
+ /home/ded/.rbenv/rbenv.d/exec/gem-rehash
27
+ /home/ded/.rbenv/versions/3.2.2/lib/ruby/site_ruby/3.2.0
28
+ /home/ded/.rbenv/versions/3.2.2/lib/ruby/site_ruby/3.2.0/x86_64-linux
29
+ /home/ded/.rbenv/versions/3.2.2/lib/ruby/site_ruby
30
+ /home/ded/.rbenv/versions/3.2.2/lib/ruby/vendor_ruby/3.2.0
31
+ /home/ded/.rbenv/versions/3.2.2/lib/ruby/vendor_ruby/3.2.0/x86_64-linux
32
+ /home/ded/.rbenv/versions/3.2.2/lib/ruby/vendor_ruby
33
+ /home/ded/.rbenv/versions/3.2.2/lib/ruby/3.2.0
34
+ /home/ded/.rbenv/versions/3.2.2/lib/ruby/3.2.0/x86_64-linux
35
+ ...
36
+ #+end_example
37
+
38
+
39
+ * Table of Contents :toc:noexport:
40
+ - [[#version][Version]]
41
+ - [[#fatcore][FatCore]]
42
+ - [[#installation][Installation]]
43
+ - [[#usage][Usage]]
44
+ - [[#array][Array]]
45
+ - [[#method-comma_joinsep-nil-last_sep-nil-two_sep-nil][Method ~#comma_join(sep: nil, last_sep: nil, two_sep: nil)~]]
46
+ - [[#method-last_i][Method ~#last_i~]]
47
+ - [[#method-intersect_with_dups][Method ~#intersect_with_dups~]]
48
+ - [[#method-diff_with_dups][Method ~diff_with_dups~]]
49
+ - [[#bigdecimal-inspect][BigDecimal ~#inspect~]]
50
+ - [[#enumerable][Enumerable]]
51
+ - [[#method-each_with_flags][Method ~#each_with_flags~]]
52
+ - [[#hash][Hash]]
53
+ - [[#method-each_pair_with_flags][Method ~#each_pair_with_flags~]]
54
+ - [[#method-delete_with_value-and-delete_with_value][Method ~#delete_with_value~ and ~#delete_with_value!~]]
55
+ - [[#method-keys_with_value][Method ~#keys_with_value~]]
56
+ - [[#method-remap_keys][Method ~#remap_keys~]]
57
+ - [[#method-replace_keys][Method ~#replace_keys~]]
58
+ - [[#alias-merge-to-][Alias ~#merge~ to ~<<~]]
59
+ - [[#numeric][Numeric]]
60
+ - [[#method-signum][Method ~#signum~]]
61
+ - [[#method-commasplaces--nil][Method ~#commas(places = nil)~]]
62
+ - [[#methods-whole-and-int_if_whole][Methods ~#whole?~ and ~#int_if_whole~]]
63
+ - [[#method-secs_to_hms][Method ~#secs_to_hms~]]
64
+ - [[#range][Range]]
65
+ - [[#methods-contiguous-left_contiguous-right_contiguous][Methods ~#contiguous~, ~#left_contiguous~, ~#right_contiguous~]]
66
+ - [[#method-joinother][Method ~#join(other)~]]
67
+ - [[#method-spanned_byothers][Method ~#spanned_by?(others)~]]
68
+ - [[#methods-gapsothers-overlapsothers][Methods ~#gaps(others)~, ~#overlaps(others)~]]
69
+ - [[#string][String]]
70
+ - [[#method-fuzzy_match][Method ~#fuzzy_match~]]
71
+ - [[#method-matches_with][Method ~#matches_with~]]
72
+ - [[#method-entitle][Method ~#entitle~]]
73
+ - [[#method-distance][Method ~#distance~]]
74
+ - [[#method-commasplaces][Method ~#commas(places)~]]
75
+ - [[#method-wrapwidth-hang][Method =#wrap(width, hang)=]]
76
+ - [[#method-as_sym][Method =#as_sym=]]
77
+ - [[#symbol][Symbol]]
78
+ - [[#method-as_str][Method =#as_str=]]
79
+ - [[#tex-quoting][TeX Quoting]]
80
+ - [[#contributing][Contributing]]
81
+
82
+ * Version
83
+ #+begin_src ruby
84
+ require_relative './lib/fat_core/version'
85
+ "Current version is: #{FatCore::VERSION}"
86
+ #+end_src
87
+
88
+ #+begin_example
89
+ Current version is: 7.0.0
90
+ #+end_example
2
91
 
3
92
  * FatCore
4
93
 
5
- ~fat-core~ is a simple gem to collect core extensions and a few new classes
6
- that I find useful in multiple projects. The emphasis is on extending the
7
- Date class to make it more useful in financial applications.
94
+ ~fat-core~ is somewhat of a grab bag of core class extensions that I have
95
+ found useful across several projects. It's higgeldy-piggeldy nature reflects
96
+ the fact that none of them are important enough to deserve a gem of their own,
97
+ but nonetheless need to be collected in one place to reduce redundancy across
98
+ projects and provide a focused place to develop and test them.
8
99
 
9
- ** Installation
100
+ * Installation
10
101
 
11
102
  Add this line to your application's Gemfile:
12
103
 
13
- #+begin_SRC ruby
14
- gem 'fat_core', :git => 'https://github.com/ddoherty03/fat_core.git'
104
+ #+begin_src ruby
105
+ gem 'fat_core'
15
106
  #+end_SRC
16
107
 
17
108
  And then execute:
@@ -26,14 +117,13 @@ Or install it yourself as:
26
117
  $ gem install fat_core
27
118
  #+end_src
28
119
 
29
- ** Usage
120
+ * Usage
30
121
 
31
122
  You can extend classes individually by requiring the corresponding file:
32
123
 
33
124
  #+begin_SRC ruby
34
125
  require 'fat_core/array'
35
126
  require 'fat_core/bigdecimal'
36
- require 'fat_core/date'
37
127
  require 'fat_core/enumerable'
38
128
  require 'fat_core/hash'
39
129
  require 'fat_core/kernel'
@@ -43,7 +133,6 @@ You can extend classes individually by requiring the corresponding file:
43
133
  require 'fat_core/symbol'
44
134
  #+end_SRC
45
135
 
46
-
47
136
  Or, you can require them all:
48
137
 
49
138
  #+begin_SRC ruby
@@ -53,454 +142,642 @@ Or, you can require them all:
53
142
  Many of these have little that is of general interest, but there are a few
54
143
  goodies.
55
144
 
56
- *** Date
57
- **** Constants
58
- ~FatCore~ adds two date constants to the ~Date~ class, Date::BOT and
59
- Date::EOT. These represent the earliest and latest dates of practical
60
- commercial interest. The exact values are rather arbitrary, but they prove
61
- useful in date ranges, for example. They are defined as:
62
-
63
- - ~Date::BOT~ :: January 1, 1900
64
- - ~Date::EOT~ :: December 31, 3000
65
- - ~Date::FEDERAL_DECREED_HOLIDAYS~ :: an Array of dates declared as non-work
66
- days for federal employees by presidential proclamation
67
- - ~Date::PRESIDENTIAL_FUNERALS~ :: an Array of dates of presidential funerals,
68
- which are observed with a closing of most federal agencies
69
-
70
- **** Ensure
71
- The ~Date.ensure~ class method tries to convert its argument to a ~Date~
72
- object by (1) applying the ~#to_date~ method or (2) applying the ~Date.parse~
73
- method to a String. This is handy when you want to define a method that takes
74
- a date argument but want the caller to be able to supply anything that can
75
- reasonably be converted to a ~Date~:
145
+ *** Array
146
+ **** Method ~#comma_join(sep: nil, last_sep: nil, two_sep: nil)~
147
+ Convert this array into a single string by (1) applying ~#to_s~ to each
148
+ element and (2) joining the elements with the string given by the ~sep:~
149
+ parameter. By default the sep parameter is ', '.
150
+
151
+ You may use a different separation string in the case when there are only two
152
+ items in the list by supplying a ~two_sep~ parameter.
153
+
154
+ You may also supply a difference separation string to separate the second-last
155
+ and last items in the array by supplying a ~last_sep:~ parameter.
156
+
157
+ By default, the sep parameter is the string ', ', the ~two_sep~ is ' and ',
158
+ and the ~last_sep~ is ', and ', all of which makes for a well-punctuated
159
+ English clause.
160
+
161
+ If ~sep~ is given, the other two parameters are set to its
162
+ value by default. If ~last_sep~ is given, ~two_sep~ takes its value by
163
+ default.
164
+
165
+ If the input array is empty, ~#comma_join~ returns an empty string.
76
166
 
77
167
  #+begin_src ruby
78
- $:.unshift("~/src/fat_core/lib")
79
- require 'fat_core/date' # => true
80
-
81
- def tomorow_tomorrow(arg)
82
- from = Date.ensure(arg) # => ArgumentError: cannot convert class 'Array' to a Date or DateTime
83
- from + 2.days # => Mon, 03 Jun 2024, Wed, 16 Oct 2024 05:47:30 -0500, Sun, 03 Mar 2024
84
- end # => :tomorow_tomorrow
85
-
86
- tomorow_tomorrow('June 1') # => Mon, 03 Jun 2024
87
- tomorow_tomorrow(Time.now) # => Wed, 16 Oct 2024 05:47:30 -0500
88
- # But it's only as good as Date.parse!
89
- tomorow_tomorrow('Ides of March') # => Sun, 03 Mar 2024
90
-
91
- tomorow_tomorrow([])
92
- # =>
93
-
94
- # ~> ArgumentError
95
- # ~> cannot convert class 'Array' to a Date or DateTime
96
- # ~>
97
- # ~> /home/ded/src/fat_core/lib/fat_core/date.rb:1849:in `ensure_date'
98
- # ~> /home/ded/src/fat_core/lib/fat_core/date.rb:1863:in `ensure'
99
- # ~> /tmp/seeing_is_believing_temp_dir20241014-1457038-xj4k5x/program.rb:5:in `tomorow_tomorrow'
100
- # ~> /tmp/seeing_is_believing_temp_dir20241014-1457038-xj4k5x/program.rb:14:in `<main>'
101
- #+end_src
102
-
103
- **** Formatting
104
-
105
- ~FatCore~ provides some concise methods for printing string versions of dates
106
- that are often useful:
107
-
108
- #+begin_SRC ruby :results output :wrap example :exports both
109
- require 'fat_core/date'
110
- d = Date.parse('1957-09-22')
111
- puts "ISO: #{d.iso}"
112
- puts "All Numbers: #{d.num}"
113
- puts "Emacs Org Mode Inactive: #{d.org}"
114
- puts "Emacs Org Mode Active: #{d.org(true)}"
115
- puts "LaTeX: #{d.tex_quote}"
116
- puts "English: #{d.eng}"
117
- puts "American: #{d.american}"
118
- #+end_SRC
168
+ require_relative 'lib/fat_core/array'
169
+
170
+ %w{hammers nails glue bolts}.comma_join
171
+ #+end_src
119
172
 
120
173
  #+begin_example
121
- ISO: 1957-09-22
122
- All Numbers: 19570922
123
- Emacs Org Mode Inactive: [1957-09-22 Sun]
124
- Emacs Org Mode Active: <1957-09-22 Sun>
125
- LaTeX: 1957--09--22
126
- English: September 22, 1957
127
- American: 9/22/1957
128
- #+end_example
129
-
130
- Most of these are self-explanatory, but a couple are not. The ~#org~ method
131
- formats a date as an Emacs org-mode timestamp, by default an inactive
132
- timestamp that does not show up in the org agenda, but can be made active with
133
- the optional parameter set to a truthy value. See
134
- [[https://orgmode.org/manual/Timestamps.html#Timestamps]].
135
-
136
- The ~#tex_quote~ method formats the date in iso form but using TeX's
137
- convention of using en-dashes to separate the components.
138
-
139
- **** Chunks
140
-
141
- Many of the methods provided by ~FatCore~ deal with various calendar periods
142
- that are less common than those provided by the Ruby Standard Library or gems
143
- such as ~active_support~. This documentation refers to these calendar periods
144
- as "chunks", and they are the following:
145
-
146
- - year,
147
- - half,
148
- - quarter,
149
- - bimonth,
150
- - month,
151
- - semimonth,
152
- - biweek,
153
- - week, and
154
- - day
155
-
156
- ~FatCore~ provides methods that query whether the date falls on the beginning
157
- or end of each of these chunks:
158
-
159
- #+begin_SRC ruby :wrap example :exports both
160
- require 'fat_core/date'
161
-
162
- tab = []
163
- d = Date.parse('2017-06-30')
164
- %i[beginning end].each do |side|
165
- %i(year half quarter bimonth month semimonth biweek week).each do |chunk|
166
- meth = "#{side}_of_#{chunk}?".to_sym
167
- tab << [d.iso, meth.to_s, "#{d.send(meth)}"]
168
- end
169
- end
170
- tab
171
- #+end_SRC
174
+ hammers, nails, glue, and bolts
175
+ #+end_example
176
+
177
+ #+begin_src ruby
178
+ require_relative 'lib/fat_core/array'
179
+
180
+ %w{hammers nails}.comma_join
181
+ #+end_src
172
182
 
173
- #+RESULTS:
174
183
  #+begin_example
175
- | 2017-06-30 | beginning_of_year? | false |
176
- | 2017-06-30 | beginning_of_half? | false |
177
- | 2017-06-30 | beginning_of_quarter? | false |
178
- | 2017-06-30 | beginning_of_bimonth? | false |
179
- | 2017-06-30 | beginning_of_month? | false |
180
- | 2017-06-30 | beginning_of_semimonth? | false |
181
- | 2017-06-30 | beginning_of_biweek? | false |
182
- | 2017-06-30 | beginning_of_week? | false |
183
- | 2017-06-30 | end_of_year? | false |
184
- | 2017-06-30 | end_of_half? | true |
185
- | 2017-06-30 | end_of_quarter? | true |
186
- | 2017-06-30 | end_of_bimonth? | true |
187
- | 2017-06-30 | end_of_month? | true |
188
- | 2017-06-30 | end_of_semimonth? | true |
189
- | 2017-06-30 | end_of_biweek? | false |
190
- | 2017-06-30 | end_of_week? | false |
191
- #+end_example
192
-
193
- It also provides corresponding methods that return the date at the beginning
194
- or end of the calendar chunk, starting at the given date:
195
-
196
- #+begin_SRC ruby :wrap example :exports both
197
- require 'fat_core/date'
198
-
199
- tab = []
200
- d = Date.parse('2017-04-21')
201
- %i[beginning end].each do |side|
202
- %i(year half quarter bimonth month semimonth biweek week ).each do |chunk|
203
- meth = "#{side}_of_#{chunk}".to_sym
204
- tab << [d.iso, "d.#{meth}", "#{d.send(meth)}"]
205
- end
184
+ hammers and nails
185
+ #+end_example
186
+
187
+ And, if you are ideologically opposed to the Oxford comma:
188
+
189
+ #+begin_src ruby
190
+ require_relative 'lib/fat_core/array'
191
+
192
+ %w{hammers nails glue bolts}.comma_join(last_sep: ' and ')
193
+ #+end_src
194
+
195
+ #+begin_example
196
+ hammers, nails, glue and bolts
197
+ #+end_example
198
+
199
+ **** Method ~#last_i~
200
+ Return the index of the last element of the Array.
201
+
202
+ #+begin_src ruby
203
+ require_relative 'lib/fat_core/array'
204
+
205
+ %w{hammers nails glue bolts}.last_i
206
+ #+end_src
207
+
208
+ #+begin_example
209
+ 3
210
+ #+end_example
211
+
212
+ **** Method ~#intersect_with_dups~
213
+ Return a new Array that is the intersection of this Array with all ~others~,
214
+ but without removing duplicates as the ~Array#&~ method does. All items of
215
+ this Array are included in the result but only if they also appear in all of
216
+ the other Arrays.
217
+
218
+ #+begin_src ruby
219
+ require_relative 'lib/fat_core/array'
220
+
221
+ a = %w{hammers nails glue bolts nails}
222
+ b = %w{nails fingers knuckles nails}
223
+ a.intersect_with_dups(b)
224
+ #+end_src
225
+
226
+ #+begin_example
227
+ | nails | nails |
228
+ #+end_example
229
+
230
+ **** Method ~diff_with_dups~
231
+ Return an Array that is the difference between this Array and =other=, but
232
+ without removing duplicates as the Array#- method does. All items of this
233
+ Array are included in the result /unless/ they also appear in any of the
234
+ =other= Arrays.
235
+
236
+ #+begin_src ruby
237
+ require_relative 'lib/fat_core/array'
238
+
239
+ a = %w{hammers nails glue bolts hammers nails}
240
+ b = %w{nails fingers knuckles nails}
241
+ a.diff_with_dups(b)
242
+ #+end_src
243
+
244
+ #+begin_example
245
+ | hammers | glue | bolts | hammers |
246
+ #+end_example
247
+
248
+ *** BigDecimal ~#inspect~
249
+ ~FatCore~ provides nothing but a better ~#inspect~ method for the ~BigDecimal~
250
+ class since the default inspect method is not very readable.
251
+
252
+ #+begin_src ruby
253
+ require_relative 'lib/fat_core/bigdecimal'
254
+
255
+ BigDecimal('2.1718281828').inspect
256
+ #+end_src
257
+
258
+ #+begin_example
259
+ 2.1718281828
260
+ #+end_example
261
+
262
+ Without ~FatCore~, the result is "0.2718281828e1", forcing you to interpret
263
+ the exponent to understand where the decimal place is.
264
+
265
+ *** Enumerable
266
+ **** Method ~#each_with_flags~
267
+ ~FatCore::Enumerable~ extends ~Enumerable~ with the ~#each_with_flags~ method
268
+ that yields the elements of the ~Enumerable~ but also yields two booleans,
269
+ ~first~ and ~last~ that are set to ~true~ on respectively, the first and last
270
+ element of the Enumerable and ~false~ otherwise. This makes it easy to treat
271
+ these two cases specially without testing the index as in ~#each_with_index~.
272
+
273
+ #+begin_src ruby
274
+ require_relative 'lib/fat_core/enumerable'
275
+
276
+ result = []
277
+ fibs = %w{1, 1, 2, 3, 5, 8, 13, 21}
278
+ fibs.each_with_flags do |f, first, last|
279
+ result <<
280
+ if first
281
+ ["Start", f]
282
+ elsif last
283
+ ["Last", f]
284
+ else
285
+ ["Continue", f]
286
+ end
206
287
  end
207
- tab
208
- #+end_SRC
288
+ result
289
+ #+end_src
209
290
 
210
- #+RESULTS:
211
291
  #+begin_example
212
- | 2017-04-21 | d.beginning_of_year | 2017-01-01 |
213
- | 2017-04-21 | d.beginning_of_half | 2017-01-01 |
214
- | 2017-04-21 | d.beginning_of_quarter | 2017-04-01 |
215
- | 2017-04-21 | d.beginning_of_bimonth | 2017-03-01 |
216
- | 2017-04-21 | d.beginning_of_month | 2017-04-01 |
217
- | 2017-04-21 | d.beginning_of_semimonth | 2017-04-16 |
218
- | 2017-04-21 | d.beginning_of_biweek | 2017-04-10 |
219
- | 2017-04-21 | d.beginning_of_week | 2017-04-17 |
220
- | 2017-04-21 | d.end_of_year | 2017-12-31 |
221
- | 2017-04-21 | d.end_of_half | 2017-06-30 |
222
- | 2017-04-21 | d.end_of_quarter | 2017-06-30 |
223
- | 2017-04-21 | d.end_of_bimonth | 2017-04-30 |
224
- | 2017-04-21 | d.end_of_month | 2017-04-30 |
225
- | 2017-04-21 | d.end_of_semimonth | 2017-04-30 |
226
- | 2017-04-21 | d.end_of_biweek | 2017-04-23 |
227
- | 2017-04-21 | d.end_of_week | 2017-04-23 |
228
- #+end_example
229
-
230
- You can query which numerical half, quarter, etc. that a given date falls in:
231
-
232
- #+begin_SRC ruby :exports both :wrap example
233
- require 'fat_core/date'
234
-
235
- tab = []
236
- %i(year half quarter bimonth month semimonth biweek week ).each do |chunk|
237
- d = Date.parse('2017-04-21') + rand(100)
238
- meth = "#{chunk}".to_sym
239
- tab << [d.iso, "d.#{meth}", "in #{chunk} number #{d.send(meth)}"]
292
+ | Start | 1, |
293
+ | Continue | 1, |
294
+ | Continue | 2, |
295
+ | Continue | 3, |
296
+ | Continue | 5, |
297
+ | Continue | 8, |
298
+ | Continue | 13, |
299
+ | Last | 21 |
300
+ #+end_example
301
+
302
+ *** Hash
303
+ FatCore::Hash extends the Hash class with some useful methods.
304
+
305
+ **** Method ~#each_pair_with_flags~
306
+ As with the extension for ~Enumerables~, ~FatCore~ provides a method for
307
+ enumerating the key-value pair of the ~Hash~ with flags that are set ~true~
308
+ for the first and last elements but ~false~ otherwise:
309
+
310
+ #+begin_src ruby
311
+ require_relative './lib/fat_core/hash'
312
+
313
+ h = {'Chaucer' => 'Cantebury Tales', 'Shakespeare' => 'The Merchant of Venice',
314
+ 'Austen' => 'Pride and Prejudice', 'C. Brontë' => 'Jane Eyre',
315
+ 'E. Brontë' => 'Wuthering Heights' }
316
+ result = []
317
+ result << ['Position', 'Author', 'Novel']
318
+ result << nil
319
+ h.each_pair_with_flags do |k, v, first, last|
320
+ pos=
321
+ if first
322
+ 'Begin'
323
+ elsif last
324
+ 'End'
325
+ else
326
+ 'Middle'
327
+ end
328
+ result << [pos, k, v]
240
329
  end
241
- tab
242
- #+end_SRC
330
+ result
331
+ #+end_src
332
+
333
+ #+begin_example
334
+ | Position | Author | Novel |
335
+ |----------+-------------+------------------------|
336
+ | Begin | Chaucer | Cantebury Tales |
337
+ | Middle | Shakespeare | The Merchant of Venice |
338
+ | Middle | Austen | Pride and Prejudice |
339
+ | Middle | C. Brontë | Jane Eyre |
340
+ | End | E. Brontë | Wuthering Heights |
341
+ #+end_example
342
+
343
+ **** Method ~#delete_with_value~ and ~#delete_with_value!~
344
+ This method modifies a ~Hash~ by deleting the key-value pairs when the value
345
+ equals the given value or values:
346
+
347
+ #+begin_src ruby :results output
348
+ require_relative './lib/fat_core/hash'
349
+
350
+ h = { a: 1, b: 2, c: 3, d: 2, e: 1 }
351
+ h.delete_with_value!(2)
352
+ puts h
353
+ #+end_src
354
+
355
+ #+begin_example
356
+ {:a=>1, :c=>3, :e=>1}
357
+ #+end_example
358
+
359
+ You can supply multiple values for deletion:
360
+
361
+ #+begin_src ruby :results output
362
+ require_relative './lib/fat_core/hash'
363
+
364
+ h = { a: 1, b: 2, c: 3, d: 2, e: 1 }
365
+ h.delete_with_value!(1, 3)
366
+ puts h
367
+ #+end_src
368
+
369
+ #+begin_example
370
+ {:b=>2, :d=>2}
371
+ #+end_example
372
+
373
+ The non-bang method returns a clone of the Hash with the given deletions made:
374
+
375
+ #+begin_src ruby :results output
376
+ require_relative './lib/fat_core/hash'
377
+
378
+ h = { a: 1, b: 2, c: 3, d: 2, e: 1 }
379
+ h2 = h.delete_with_value(1, 3)
380
+ puts h
381
+ puts h2
382
+ #+end_src
383
+
384
+ #+begin_example
385
+ {:a=>1, :b=>2, :c=>3, :d=>2, :e=>1}
386
+ {:b=>2, :d=>2}
387
+ #+end_example
388
+
389
+ **** Method ~#keys_with_value~
390
+ Return an ~Array~ of keys of the ~Hash~ with a value ~==~ to the given value
391
+ or values.
392
+
393
+ #+begin_src ruby :results output
394
+ require_relative './lib/fat_core/hash'
395
+
396
+ h = { a: 1, b: 2, c: 3, d: 2, e: 1 }
397
+ puts h.keys_with_value(1).inspect
398
+ puts h.keys_with_value(2, 3).inspect
399
+ #+end_src
400
+
401
+ #+begin_example
402
+ [:a, :e]
403
+ [:b, :d, :c]
404
+ #+end_example
405
+
406
+ **** Method ~#remap_keys~
407
+ This method pre-dates the new ~#transform_keys~ method now available for
408
+ ~Hash~, but it is kept as an alternative. It takes a ~Hash~ as an argument
409
+ that maps existing keys to their replacement in the resulting ~Hash~. The
410
+ original ~Hash~ is not effected.
411
+
412
+ #+begin_src ruby :results output
413
+ require_relative './lib/fat_core/hash'
414
+
415
+ h = { a: 1, b: 2, c: 3, d: 2, e: 1 }
416
+ puts h.remap_keys({:a => :A, :b => :B}).inspect
417
+ #+end_src
243
418
 
244
- #+RESULTS:
245
419
  #+begin_example
246
- | 2017-07-05 | d.year | in year number 2017 |
247
- | 2017-06-03 | d.half | in half number 1 |
248
- | 2017-05-30 | d.quarter | in quarter number 2 |
249
- | 2017-07-08 | d.bimonth | in bimonth number 4 |
250
- | 2017-06-28 | d.month | in month number 6 |
251
- | 2017-05-14 | d.semimonth | in semimonth number 9 |
252
- | 2017-07-25 | d.biweek | in biweek number 15 |
253
- | 2017-06-19 | d.week | in week number 25 |
420
+ {:A=>1, :B=>2, :c=>3, :d=>2, :e=>1}
254
421
  #+end_example
255
422
 
256
- **** Parsing
423
+ These days, a more systematic job could be done with ~#transform_keys~:
424
+ #+begin_src ruby :results output
425
+ h = { a: 1, b: 2, c: 3, d: 2, e: 1 }
426
+ puts h.transform_keys { |k| k.to_s.upcase.to_sym }.inspect
427
+ #+end_src
428
+
429
+ #+begin_example
430
+ {:A=>1, :B=>2, :C=>3, :D=>2, :E=>1}
431
+ #+end_example
257
432
 
258
- ~FatCore~ also adds some convenience methods for parsing strings as ~Date~
259
- objects.
433
+ **** Method ~#replace_keys~
434
+ A wholesale replacement of the existing keys can be done with this method:
260
435
 
261
- ***** American Dates
262
- Americans often write dates in the form M/d/Y, and the normal parse method
263
- will parse such a string as d/M/Y, often resulting in invalid date errors.
264
- ~FatCore~ adds the specialty parsing method, ~Date.parse_american~ to handle
265
- such strings.
436
+ #+begin_src ruby :results output
437
+ require_relative './lib/fat_core/hash'
266
438
 
267
- #+begin_SRC ruby :results output :exports both :wrap example
268
- require 'fat_core/date'
439
+ h = { a: 1, b: 2, c: 3, d: 2, e: 1 }
440
+ puts h
441
+ puts h.replace_keys([:z, :y, :x, :w, :v]).inspect
442
+ #+end_src
443
+
444
+ #+begin_example
445
+ {:a=>1, :b=>2, :c=>3, :d=>2, :e=>1}
446
+ {:z=>1, :y=>2, :x=>3, :w=>2, :v=>1}
447
+ #+end_example
448
+
449
+ **** Alias ~#merge~ to ~<<~
450
+ Finally, ~FatCore~ adds the "shovel" operator as an alias for ~#merge~ to
451
+ provide a pretty way to represent the merger of the right ~Hash~ into the left
452
+ ~Hash~:
453
+
454
+ #+begin_src ruby :results output
455
+ require_relative './lib/fat_core/hash'
456
+
457
+ h = {a: 'A', b: 'B', c: 'C'} << {c: 'CC', d: 'DD'} << {d: 'DDD', e: 'EEE'}
458
+ puts h
459
+ #+end_src
269
460
 
270
- begin
271
- ss = '9/22/1957'
272
- Date.parse(ss)
273
- rescue Date::Error => ex
274
- puts "Date.parse('#{ss}') raises #{ex.class} (#{ex}), but"
275
- puts "Date.parse_american('#{ss}') => #{Date.parse_american(ss)}"
461
+ #+begin_example
462
+ {:a=>"A", :b=>"B", :c=>"CC", :d=>"DDD", :e=>"EEE"}
463
+ #+end_example
464
+
465
+ It groups values into pairs and applies the ~#to_h~ method to the right-hand
466
+ argument if it is an ~Enumerable~, so it also works if the right-hand argument
467
+ is an ~Array~ or ~Enumerable~:
468
+
469
+ #+begin_src ruby :results output
470
+ require 'fileutils'
471
+ require_relative './lib/fat_core/hash'
472
+
473
+ FileUtils.mkdir_p('./tmp')
474
+ ff = File.open('./tmp/junk', 'w')
475
+ ff.write("f\n", "FFFF\n", "g\n", "GGGG\n")
476
+ ff.close
477
+ ff = File.open('./tmp/junk', 'r')
478
+ h = {a: 'A', b: 'B', c: 'C'} <<
479
+ [:c, 'CC', :d, 'DD'] <<
480
+ {d: 'DDD', e: 'EEE'} <<
481
+ ff.readlines.map(&:chomp) <<
482
+ [[:h, 'HHHHH'], [:j, 'JJJJJ']]
483
+ # h.transform_keys!(&:to_sym)
484
+ ff.close
485
+ FileUtils.rm_rf('./tmp/junk')
486
+ puts h
487
+ #+end_src
488
+
489
+ #+begin_example
490
+ {:a=>"A", :b=>"B", :c=>"CC", :d=>"DDD", :e=>"EEE", "f"=>"FFFF", "g"=>"GGGG", :h=>"HHHHH", :j=>"JJJJJ"}
491
+ #+end_example
492
+
493
+ *** Numeric
494
+ **** Method ~#signum~
495
+ Return ~-1~ for negative numbers, ~0~ for zero, and ~+1~ for positive numbers.
496
+ This is sometimes handy.
497
+
498
+ **** Method ~#commas(places = nil)~
499
+ To get s ~String~ representation of a ~Numeric~ with grouping commas inserted,
500
+ ~FatCore~ provides the ~#commas~ method:
501
+
502
+ #+begin_src ruby
503
+ require_relative 'lib/fat_core/numeric'
504
+ result = []
505
+ result << ['N', 'Places', 'N.commas(places)']
506
+ result << nil
507
+ nums = [3.14159, 2.718281828, 100000, 0.0059, 16236565468798.66877]
508
+ places = [0, 3, 5]
509
+ nums.each do |n|
510
+ places.each do |pl|
511
+ result << [n, pl, n.commas(pl)]
512
+ end
276
513
  end
277
- #+end_SRC
514
+ result
515
+ #+end_src
278
516
 
279
- #+RESULTS:
280
517
  #+begin_example
281
- Date.parse('9/22/1957') raises Date::Error (invalid date), but
282
- Date.parse_american('9/22/1957') => 1957-09-22
283
- #+end_example
284
-
285
- ***** Date Specs
286
- It is often desirable to get the first or last date of a specified time
287
- period. For this ~FatCore~ provides the ~parse_spec~ method that takes a
288
- string and an optional ~spec_type~ parameter of either ~:from~, indicating
289
- that the first date of the period should be returned or ~:to~, indicating that
290
- the last date of the period should be returned.
291
-
292
- This method supports a rich set of ways to specify periods of time:
293
-
294
- - YYYY-MM-DD :: returns a single day as the time period,
295
- - YYYY-MM :: returns the specified month, beginning or end
296
- - YYYY :: returns the specified year, beginning or end
297
- - YYYY-ddd :: returns the ddd'th day of the specified year, beginning or end
298
- - MM :: returns the specified month of the current year, beginning or end
299
- - MM-DD :: returns the specified day of the specified month in the current
300
- year, beginning or end,
301
- - YYYY-Wnn or YYYY-nnW :: returns the nn'th commercial week of the given year
302
- according to the ISO 8601 standard, in which the week containing the first
303
- Thursday of the year counts as the first commercial week, even if that week
304
- started in the prior calendar year,
305
- - Wnn or nnW :: returns the nn'th commercial week of the current year,
306
- - YYYY-1H or YYYY-2H :: returns the specified half year for the given year,
307
- - 1H or 2H :: returns the specified half year for the current year,
308
- - YYYY-1Q, YYYY-2Q, etc :: returns the calendar quarter for the given year,
309
- - 1Q, 2Q, etc :: returns the calendar quarter for the current year,
310
- - YYYY-MM-I or YYYY-MM-II :: returns the semi-month for the given month and
311
- year, where the first semi-month always runs from the 1st to the 15th and
312
- the second semi-month always runs from the 16th to the last day of the given
313
- month, regardless of the number of days in the month,
314
- - YYYY-MM-i or YYYY-MM-ii up to YYYY-MM-vi :: returns the given week within
315
- the month, including any partial weeks,
316
- - MM-i or MM-ii up to MM-vi :: returns the given week within the month of the
317
- current year, including any partial weeks,
318
- - i or ii up to vi :: returns the given week within the current month of the current
319
- year, including any partial weeks,
320
- - YYYY-MM-nSu up to YYYY-MM-nSa :: returns the single date that is the n'th
321
- Sunday, Monday, etc., in the given month using the first two letters of the
322
- English names for the days of the week,
323
- - MM-nSu up to MM-nSa :: returns the single date that is the n'th Sunday,
324
- Monday, etc., in the given month of the current year using the first two
325
- letters of the English names for the days of the week,
326
- - nSu up to nSa :: returns the single date that is the n'th Sunday, Monday,
327
- etc., in the current month of the current year using the first two letters
328
- of the English names for the days of the week,
329
- - YYYY-nnn :: is the nnn'th day of the given year, exactly three digits needed,
330
- - nnn :: is the nnn'th day of the current year, exactly three digits needed,
331
- - YYYY-E :: returns the single date of Easter in the Western church for the
332
- given year,
333
- - E :: returns the single date of Easter in the Western church for the current
334
- year,
335
- - YYYY-E-n or YYYY-E+n :: returns the single date that falls n days before (-)
336
- or after (+) Easter in the Western church for the given year,
337
- - E-n or E+n :: returns the single date that falls n days before (-) or after
338
- (+) Easter in the Western church for the current year,
339
- - yesterday or yesteryear or lastday or last_year, etc :: the relative
340
- prefixes, 'last' or 'yester' prepended to any chunk name returns the period
341
- named by the chunk that precedes today's date.
342
- - today or toyear or this-year or thissemimonth, etc :: the relative prefixes,
343
- 'to' or 'this' prepended to any chunk name returns the period named by
344
- the chunk that contains today's date.
345
- - nextday or nextyear or next-year or nextsemimonth, etc :: the relative
346
- prefixes, 'next' prepended to any chunk name returns the period named by the
347
- chunk that follows today's date. As a special case, 'tomorrow' is treated as
348
- equivalent to 'nextday'.
349
- - forever :: returns the period Date::BOT to Date::EOT, which, for financial
350
- applications is meant to stand in for eternity.
351
- - never :: returns nil, representing no date.
352
-
353
- Some things to note with respect to ~Date.parse_spec~:
354
-
355
- 1. The second argument should be either ~:from~ or ~:to~, but it defaults to
356
- ~:from~. If it is ~:from~, ~parse_spec~ returns the first date of the
357
- specified period; if it is ~:to~, it returns the last date of the specified
358
- period. When the "period" resolves to a single day, both arguments return
359
- the same date, so ~parse_spec('2024-E', :from)~ and ~parse_spec('2024-E',
360
- :to)~ both result in March 31, 2024.
361
- 2. Where relevant, ~parse_spec~ accepts letters of either upper or lower case:
362
- so 2024-1Q can be written 2024-1q and 'yesteryear' can be written
363
- 'YeSterYeaR', and likewise for all components of the spec using letters.
364
- 3. Date components can be separated with either a hyphen, as in the examples
365
- above, or with a '/' as is common. Thus, 2024-11-09 can also be
366
- 2024/11/09, or indeed, 2024/11-09 or 2024-11/09.
367
- 4. The prefixes for relative periods can be separated from the period name by
368
- a hyphen, and underscore, or by nothing at all. Thus, yester-day,
369
- yester_day, and yesterday are all acceptable. Clearly neologisms such as
370
- 'yestermonth' are quaint, but not harmful.
371
- 5. On the other hand, to get a day-of-year spec right, you must use exactly 3
372
- digits: 2024-011 is the 11th day of 2024, but 2024-11 is November of 2024.
373
-
374
- **** Holidays and Workdays
375
- One of the original motivations for this library was to provide an easy way to
376
- determine whether a given date is a federal holiday in the United States or,
377
- nearly but not quite the same, a non-trading day on the New York Stock
378
- Exchange. To that end, ~FatCore~ provides the following methods:
379
-
380
- - Date#weekend? -- is this date on a weekend?
381
- - Date#weekday? -- is this date on a week day?
382
- - Date#easter_this_year -- the date of Easter in the Date's year
383
-
384
- Methods concerning Federal holidays:
385
-
386
- - Date#fed_holiday? -- is this date a Federal holiday? It knows about
387
- obscurities such as holidays decreed by past Presidents, dates of
388
- Presidential funerals, and the Federal rule for when holidays fall on a
389
- weekend, whether it is moved to the prior Friday or the following Monday.
390
- - Date#fed_workday? -- is it a date when the Federal government is open?,
391
- inverse of Date#fed_holiday?
392
- - Date#add_fed_workdays(n) -- n Federal workdays following (or preceding if n
393
- negative) this date,
394
- - Date#next_fed_workday -- the next Federal workday following this date,
395
- - Date#prior_fed_workday -- the previous Federal workday before this date,
396
- - Date#next_until_fed_workday -- starting with this date, move forward until
397
- we hit a Federal workday
398
- - Date#prior_until_fed_workday -- starting with this date, move back until
399
- we hit a Federal workday
400
-
401
- And we have similar methods for "holidays" or non-trading days on the NYSE:
402
-
403
- - Date#nyse_holiday? -- is this date a NYSE holiday?
404
- - Date#nyse_workday? -- is it a date when the NYSE is open for trading?,
405
- inverse of Date#nyse_holiday?
406
- - Date#add_nyse_workdays(n) -- n NYSE workdays following (or preceding if n
407
- negative) this date,
408
- - Date#next_nyse_workday -- the next NYSE workday following this date,
409
- - Date#prior_nyse_workday -- the previous NYSE workday before this date,
410
- - Date#next_until_nyse_~~workday -- starting with this date, move forward until
411
- we hit a NYSE workday
412
- - Date#prior_until_nyse_workday -- starting with this date, move back until
413
- we hit a Federal workday
414
-
415
- **** Ordinal Weekdays in Month
416
- It is often useful to find the 1st, 2nd, etc, Sunday, Monday, etc. in a given
417
- month. ~FatCore~ provides the class method ~Date.nth_wday_in_year_month(nth,
418
- wday, year, month)~ to return such dates. The first parameter can be
419
- negative, which will count from the end of the month.
420
-
421
- **** Easter
422
- The ~Date~ class extension adds two methods for determining whether a given
423
- date is a US federal holiday as defined by federal law, including such things
424
- as federal holidays established by executive decree:
518
+ | N | Places | N.commas(places) |
519
+ |--------------------+--------+--------------------------|
520
+ | 3.14159 | 0 | 3 |
521
+ | 3.14159 | 3 | 3.142 |
522
+ | 3.14159 | 5 | 3.14159 |
523
+ | 2.718281828 | 0 | 3 |
524
+ | 2.718281828 | 3 | 2.718 |
525
+ | 2.718281828 | 5 | 2.71828 |
526
+ | 100000 | 0 | 100,000 |
527
+ | 100000 | 3 | 100,000.000 |
528
+ | 100000 | 5 | 100,000.00000 |
529
+ | 0.0059 | 0 | 0 |
530
+ | 0.0059 | 3 | 0.006 |
531
+ | 0.0059 | 5 | 0.00590 |
532
+ | 16236565468798.668 | 0 | 16,236,565,468,799 |
533
+ | 16236565468798.668 | 3 | 16,236,565,468,798.668 |
534
+ | 16236565468798.668 | 5 | 16,236,565,468,798.66800 |
535
+ #+end_example
425
536
 
426
- #+begin_SRC ruby
427
- require 'fat_core/date'
428
- Date.parse('2014-05-18').fed_holiday? => true # It's a weekend
429
- Date.parse('2014-01-01').fed_holiday? => true # It's New Years
430
- #+end_SRC
537
+ FatCore::Numeric has methods for inserting grouping commas into a number
538
+ (~#commas~ and ~#group~), for converting seconds to HH:MM:SS.dd format
539
+ (~#secs_to_hms~), for testing for integrality (~#whole?~ and ~#int_if_whole~), and
540
+ testing for sign (~#signum~).
431
541
 
432
- Likewise, days on which the NYSE is closed can be gotten with:
542
+ **** Methods ~#whole?~ and ~#int_if_whole~
543
+ At times it is useful to know if a Float or BigDecimal can be converted to an
544
+ ~Integer~ without losing precision.
433
545
 
434
- #+begin_SRC ruby
435
- Date.parse('2014-04-18').nyse_holiday? => true # It's Good Friday
436
- #+end_SRC
546
+ #+begin_src ruby
547
+ require_relative 'lib/fat_core/numeric'
548
+ result = []
549
+ result << ['N', '#whole?', '#int_if_whole', 'Classes']
550
+ result << nil
551
+ nums = [3.14159, 3.000000, 100000, 0.0059, 16236565468798.66877]
552
+ nums.each do |n|
553
+ result << [n, n.whole?, n.int_if_whole, "#{n.class} -> #{n.int_if_whole.class}"]
554
+ end
555
+ result
556
+ #+end_src
557
+
558
+ #+begin_example
559
+ | N | #whole? | #int_if_whole | Classes |
560
+ |--------------------+---------+--------------------+--------------------|
561
+ | 3.14159 | false | 3.14159 | Float -> Float |
562
+ | 3.0 | true | 3 | Float -> Integer |
563
+ | 100000 | true | 100000 | Integer -> Integer |
564
+ | 0.0059 | false | 0.0059 | Float -> Float |
565
+ | 16236565468798.668 | false | 16236565468798.668 | Float -> Float |
566
+ #+end_example
437
567
 
438
- Conversely, ~Date#fed_workday?~ and ~Date#nyse_workday?~ return true if the
439
- federal government and the NYSE respectively are open for business on those
440
- days.
568
+ **** Method ~#secs_to_hms~
569
+ This method converts a numeric representing a number of seconds or an angle in
570
+ degrees to a ~String~ of the form "HH:MM:SS" representing the same quantity in
571
+ hours, minutes, and seconds.
441
572
 
442
- In addition, the Date class, as extended by FatCore, adds ~#next_<chunk>~
443
- methods for calendar periods in addition to those provided by the core Date
444
- class: ~#next_half~, ~#next_quarter~, ~#next_bimonth~, and ~#next_semimonth~,
445
- ~#next_biweek~. There are also ~#prior_<chunk>~ variants of these, as well as
446
- methods for finding the end and beginning of all these periods (e.g.,
447
- ~#beginning_of_bimonth~) and for querying whether a Date is at the beginning or
448
- end of these periods (e.g., ~#beginning_of_bimonth?~, ~#end_of_bimonth?~, etc.).
573
+ #+begin_src ruby
574
+ require_relative 'lib/fat_core/numeric'
575
+ result = []
576
+ result << ['N', 'HH:MM:SS']
577
+ result << nil
578
+ nums = [85777.66, 959.66, -1198.33, 0, 3.14159 * 180]
579
+ nums.each do |n|
580
+ result << [n, n.secs_to_hms]
581
+ end
582
+ result
583
+ #+end_src
449
584
 
450
- FatCore also provides convenience formatting methods, such as ~Date#iso~ for
451
- quickly converting a Date to a string of the form 'YYYY-MM-DD', ~Date#org~ for
452
- formatting a Date as an Emacs org-mode timestamp, and several others.
585
+ #+begin_example
586
+ | N | HH:MM:SS |
587
+ |-------------------+-------------|
588
+ | 85777.66 | 23:49:37.66 |
589
+ | 959.66 | 00:15:59.66 |
590
+ | -1198.33 | -1:40:01.67 |
591
+ | 0 | 00:00:00 |
592
+ | 565.4861999999999 | 00:09:25.48 |
593
+ #+end_example
453
594
 
454
- Finally, it provides a ~#parse_spec~ method for parsing a string, typically
455
- provided by a user, allowing all the period chunks to be conveniently and
456
- tersely specified by a user. For example, the string '2Q' will be parsed as the
457
- second calendar quarter of the current year, while '2014-3Q' will be parsed as
458
- the third quarter of the year 2014.
459
595
 
460
596
  *** Range
597
+ ~FatCore~ can also extend the Range class with several useful methods that
598
+ emphasize coverage of one range by one or more others (~#spanned_by?~ and
599
+ ~#gaps~), contiguity of Ranges to one another (~#contiguous?~,
600
+ ~#left_contiguous?~, and ~#right_contiguous?~, ~#join~), and the testing of
601
+ overlaps between ranges (~#overlaps?~, ~#overlaps_among?~). These are put to
602
+ good use in the 'fat_period' ([[https://github.com/ddoherty03/fat_period]]) gem,
603
+ which combines fat_core's extended Range class with its extended Date class to
604
+ make a useful Period class for date ranges, and you may find fat_core's
605
+ extended Range class likewise useful.
606
+
607
+ **** Methods ~#contiguous~, ~#left_contiguous~, ~#right_contiguous~
608
+ These methods determine whether the subject ~Range~ are "contiguous" with
609
+ another ~Range~ on the left, right, or either side. The notion of contiguity
610
+ is different for ~Ranges~ whose min and max values respond to the ~#succ~
611
+ method: if they do, "contiguity" only requires that the ~#succ~ of the max
612
+ value of the left range equal the min value of the right ~Range~; otherwise
613
+ the max value of the left ~Range~ must equal the min value of the right
614
+ ~Range~.
461
615
 
462
- You can also extend the Range class with several useful methods that emphasize
463
- coverage of one range by one or more others (~#spanned_by?~ and ~#gaps~),
464
- contiguity of Ranges to one another (~#contiguous?~, ~#left_contiguous?~, and
465
- ~#right_contiguous?~, ~#join~), and the testing of overlaps between ranges
466
- (~#overlaps?~, ~#overlaps_among?~). These are put to good use in the
467
- 'fat_period' ([[https://github.com/ddoherty03/fat_period]]) gem, which combines
468
- fat_core's extended Range class with its extended Date class to make a useful
469
- Period class for date ranges, and you may find fat_core's extended Range class
470
- likewise useful.
616
+ #+begin_src ruby
617
+ require_relative 'lib/fat_core/range'
618
+ require 'date'
619
+
620
+ result = []
621
+ result << ["Self", "Other", "Contiguous?", "Right?", "Left?"]
622
+ result << nil
623
+ pairs = [
624
+ [(0..10), (11..12)],
625
+ [(11..20), (0..10)],
626
+ [(0..10), (15..20)],
627
+ [(3.145..12.3), (0.5..3.145)],
628
+ [(3.146..12.3), (0.5..3.145)],
629
+ [('a'..'q'), ('r'..'z')],
630
+ [('a'..'q'), ('s'..'z')],
631
+ [(Date.parse('1963-11-22')..Date.parse('1964-11-03')), (Date.parse('1964-11-04')..Date.today)],
632
+ [(Date.parse('1963-11-22')..Date.parse('1964-11-03')), (Date.parse('1964-11-28')..Date.today)]
633
+ ]
634
+ pairs.each do |r1, r2|
635
+ result << [r1.to_s, r2.to_s, r1.contiguous?(r2), r1.right_contiguous?(r2), r1.left_contiguous?(r2)]
636
+ end
637
+ result
638
+ #+end_src
471
639
 
472
- For example, you can use the ~#gaps~ method to find the gaps left in the
473
- coverage on one Range by an Array of other Ranges:
640
+ #+begin_example
641
+ | Self | Other | Contiguous? | Right? | Left? |
642
+ |------------------------+------------------------+-------------+--------+-------|
643
+ | 0..10 | 11..12 | true | true | false |
644
+ | 11..20 | 0..10 | true | false | true |
645
+ | 0..10 | 15..20 | false | false | false |
646
+ | 3.145..12.3 | 0.5..3.145 | true | false | true |
647
+ | 3.146..12.3 | 0.5..3.145 | false | false | false |
648
+ | a..q | r..z | true | true | false |
649
+ | a..q | s..z | false | false | false |
650
+ | 1963-11-22..1964-11-03 | 1964-11-04..2025-11-22 | true | true | false |
651
+ | 1963-11-22..1964-11-03 | 1964-11-28..2025-11-22 | false | false | false |
652
+ #+end_example
474
653
 
475
- #+begin_SRC ruby
476
- require 'fat_core/range'
477
- (0..12).gaps([(0..2), (5..7), (10..12)]) => [(3..4), (8..9)]
478
- #+end_SRC
654
+ **** Method ~#join(other)~
655
+ If ~self~ is contiguous with ~other~, return a new ~Range~ that splices the
656
+ two ~Range~s into one ~Range~.
479
657
 
480
- * Enumerable
481
- FatCore::Enumerable extends Enumerable with the ~#each_with_flags~ method that
482
- yields the elements of the Enumerable but also yields two booleans, ~first~ and
483
- ~last~ that are set to true on respectively, the first and last element of the
484
- Enumerable. This makes it easy to treat these two cases specially without
485
- testing the index as in ~#each_with_index~.
658
+ #+begin_src ruby
659
+ require_relative 'lib/fat_core/range'
660
+ require 'date'
661
+
662
+ result = []
663
+ result << ["Self", "Other", "Contiguous?", "Joined"]
664
+ result << nil
665
+ pairs = [
666
+ [(0..10), (11..12)],
667
+ [(11..20), (0..10)],
668
+ [(0..10), (15..20)],
669
+ [(3.145..12.3), (0.5..3.145)],
670
+ [(3.146..12.3), (0.5..3.145)],
671
+ [('a'..'q'), ('r'..'z')],
672
+ [('a'..'q'), ('s'..'z')],
673
+ [(Date.parse('1963-11-22')..Date.parse('1964-11-03')), (Date.parse('1964-11-04')..Date.today)],
674
+ [(Date.parse('1963-11-22')..Date.parse('1964-11-03')), (Date.parse('1964-11-28')..Date.today)]
675
+ ]
676
+ pairs.each do |r1, r2|
677
+ result << [r1.to_s, r2.to_s, r1.contiguous?(r2), "#{r1.join(r2)}"]
678
+ end
679
+ result
680
+ #+end_src
486
681
 
487
- *** Hash
682
+ #+begin_example
683
+ | Self | Other | Contiguous? | Joined |
684
+ |------------------------+------------------------+-------------+------------------------|
685
+ | 0..10 | 11..12 | true | 0..12 |
686
+ | 11..20 | 0..10 | true | 0..20 |
687
+ | 0..10 | 15..20 | false | |
688
+ | 3.145..12.3 | 0.5..3.145 | true | 0.5..12.3 |
689
+ | 3.146..12.3 | 0.5..3.145 | false | |
690
+ | a..q | r..z | true | a..z |
691
+ | a..q | s..z | false | |
692
+ | 1963-11-22..1964-11-03 | 1964-11-04..2025-11-22 | true | 1963-11-22..2025-11-22 |
693
+ | 1963-11-22..1964-11-03 | 1964-11-28..2025-11-22 | false | |
694
+ #+end_example
695
+
696
+
697
+ **** Method ~#spanned_by?(others)~
698
+ A set of ~Ranges~ "spans" a given ~Range~ if the set is contiguous and fully
699
+ covers the given ~Range~ with no overlaps and no gaps. A set that over-covers
700
+ the given ~Range~ is still considered to span it, even though it is wider than
701
+ the given ~Range~. In other words, a set spans the given ~Range~ if the set
702
+ can be joined and the given ~Range~ is within the joined ~Range~.
488
703
 
489
- FatCore::Hash extends the Hash class with some useful methods for element
490
- deletion (~#delete_with_value~) and for manipulating the keys
491
- (~#keys_with_value~, ~#remap_keys~ and ~#replace_keys~) of a Hash. It also
492
- provides ~#each_pair_with_flags~ as an analog to Enumerable's
493
- ~#each_with_flags~.
704
+ #+begin_src ruby
705
+ require_relative 'lib/fat_core/range'
706
+ require 'date'
707
+
708
+ result = []
709
+ result << ["Self", "Others", "Spanned By?"]
710
+ result << nil
711
+ pairs = [
712
+ [(0..10), [(-1..5), (6..10)]],
713
+ [(1..20), [(0..10), (11..20)]],
714
+ [(1..20), [(0..10), (10..20)]],
715
+ [(3.145..12.3), [(0.5..3.45), (3.45..10.5), (10.5..13.5)]],
716
+ [(3.145..12.3), [(0.5..3.45), (3.45..10.5), (10.6..13.5)]],
717
+ [('a'..'z'), [('a'..'g'), ('h'..'s'), ('t'..'z')]],
718
+ [('a'..'z'), [('a'..'g'), ('j'..'s'), ('t'..'z')]],
719
+ ]
720
+ pairs.each do |r, others|
721
+ result << ["#{r}", "#{others}", r.spanned_by?(others)]
722
+ end
723
+ result
724
+ #+end_src
494
725
 
495
- It also provides the shovel operator as a convenient alias for ~Hash#merge~,
496
- so that
726
+ #+begin_example
727
+ | Self | Others | Spanned By? |
728
+ |-------------+-------------------------------------+-------------|
729
+ | 0..10 | [-1..5, 6..10] | true |
730
+ | 1..20 | [0..10, 11..20] | true |
731
+ | 1..20 | [0..10, 10..20] | false |
732
+ | 3.145..12.3 | [0.5..3.45, 3.45..10.5, 10.5..13.5] | true |
733
+ | 3.145..12.3 | [0.5..3.45, 3.45..10.5, 10.6..13.5] | false |
734
+ | a..z | ["a".."g", "h".."s", "t".."z"] | true |
735
+ | a..z | ["a".."g", "j".."s", "t".."z"] | false |
736
+ #+end_example
497
737
 
498
- #+begin_src ruby :tangle no
499
- {a: 'A', b: 'B', c: 'C'} << {c: 'CC', d: 'DD'} << {e: 'EEE'} => {a: 'A', b: 'B', c: 'CC', d: 'DD', e: 'EEE'}
738
+ **** Methods ~#gaps(others)~, ~#overlaps(others)~
739
+ When the set of other ~Ranges~ does not span the given ~Range~, these methods
740
+ return an set of ~Ranges~ that represent the portions of the given ~Range~ no
741
+ covered by the ~others~, the "gaps", or the points within the given ~Range~
742
+ where the ~others~ overlap one another and thus are not contiguous.
743
+
744
+ #+begin_src ruby
745
+ require_relative 'lib/fat_core/range'
746
+ require 'date'
747
+
748
+ result = []
749
+ result << ["Self", "Others", "Spanned By?", "Gaps", "Overlaps"]
750
+ result << nil
751
+ pairs = [
752
+ [(0..10), [(-1..5), (6..10)]],
753
+ [(1..20), [(0..10), (11..20)]],
754
+ [(1..20), [(0..15), (11..20)]],
755
+ [(1..20), [(0..10), (10..20)]],
756
+ [(3.145..12.3), [(0.5..3.45), (3.45..10.5), (10.5..13.5)]],
757
+ [(3.145..12.3), [(0.5..3.45), (3.45..10.5), (10.6..13.5)]],
758
+ [('a'..'z'), [('a'..'g'), ('h'..'s'), ('t'..'z')]],
759
+ [('a'..'z'), [('a'..'g'), ('j'..'s'), ('t'..'z')]],
760
+ ]
761
+ pairs.each do |r, others|
762
+ result << ["#{r}", "#{others}", r.spanned_by?(others), "#{r.gaps(others)}", "#{r.overlaps(others)}"]
763
+ end
764
+ result
500
765
  #+end_src
501
766
 
502
- *** String
767
+ #+begin_example
768
+ | Self | Others | Spanned By? | Gaps | Overlaps |
769
+ |-------------+-------------------------------------+-------------+--------------+----------|
770
+ | 0..10 | [-1..5, 6..10] | true | [] | [] |
771
+ | 1..20 | [0..10, 11..20] | true | [] | [] |
772
+ | 1..20 | [0..15, 11..20] | false | [] | [11..15] |
773
+ | 1..20 | [0..10, 10..20] | false | [] | [] |
774
+ | 3.145..12.3 | [0.5..3.45, 3.45..10.5, 10.5..13.5] | true | [] | [] |
775
+ | 3.145..12.3 | [0.5..3.45, 3.45..10.5, 10.6..13.5] | false | [10.5..10.6] | [] |
776
+ | a..z | ["a".."g", "h".."s", "t".."z"] | true | [] | [] |
777
+ | a..z | ["a".."g", "j".."s", "t".."z"] | false | ["h".."i"] | [] |
778
+ #+end_example
503
779
 
780
+ *** String
504
781
  FatCore::String has methods for performing matching of one string with another
505
782
  (~#matches_with~, ~#fuzzy_match~), for converting a string to title-case as
506
783
  might by used in the title of a book (~#entitle~), for converting a String
@@ -509,21 +786,333 @@ into a useable Symbol (~#as_sym~) and vice-versa (~#as_str~ also
509
786
  cleaning up errant spaces (~#clean~), and computing the Damerau-Levenshtein
510
787
  distance between strings (~#distance~). And several others.
511
788
 
789
+ **** Method ~#fuzzy_match~
790
+ The ~#fuzzy_match~ method determines whether the subject string matches the
791
+ given "matcher" string, which provides a simple syntax that allows a limited
792
+ kind of pattern matching. If there is a match, it returns the matched portion
793
+ of self, minus punctuation characters, if self matches the string, and returns
794
+ nil otherwise.
795
+
796
+ What makes this handy is that a user trying to match by memory can be loose
797
+ about case, punctuation, and spaces, and still find desired matches. In the
798
+ matcher both the space and colon ':' have special meaning as shown below.
799
+
800
+ ~#fuzzy_match(matcher)~ uses the following rules for matching:
801
+
802
+ 1. Remove leading and trailing whitespace in the subject and the matcher
803
+ and collapse its internal whitespace to a single space,
804
+ 2. Remove all periods, commas, apostrophes, and asterisks (the
805
+ punctuation characters) from both self and `matcher`,
806
+ 3. Treat internal ':stuff' or ' :stuff' in the matcher as the equivalent
807
+ of /\bstuff.*/ in a regular expression, that is, match any word
808
+ starting with stuff in self,
809
+ 4. Treat internal 'stuff: ' in the matcher as the equivalent of /.*stuff\b/ in
810
+ a regular expression, that is, match any word ending with stuff in self,
811
+ 5. A colon with no spaces around it is treated as belonging to the
812
+ following word, requiring it to start with it, so 'some:stuff'
813
+ requires 'some' anywhere followed by a word beginning with 'stuff',
814
+ i.e., /some.*\bstuff/i,
815
+ 6. Treat leading ':' in the matcher as anchoring the match to the
816
+ beginning of the target string,
817
+ 7. Treat ending ':' in the matcher as anchoring the match to the
818
+ end of the target string,
819
+ 8. Require each component to match some part of self, and
820
+
821
+ #+begin_src ruby
822
+ require_relative './lib/fat_core/string'
823
+
824
+ result = []
825
+ result << ['Self', 'Matcher', 'Match']
826
+ result << nil
827
+ subj = "St. Luke's Hospital"
828
+ matchers = ['st lukes', 'luk:hosp', 'st:spital', 'uk spital', 'st:laks', ':lukes', 's lukes', 'lukes:hospital']
829
+ matchers.each do |m|
830
+ result << [subj, m, subj.fuzzy_match(m)]
831
+ end
832
+ result
833
+ #+end_src
834
+
835
+ #+begin_example
836
+ | Self | Matcher | Match |
837
+ |---------------------+----------------+----------------|
838
+ | St. Luke's Hospital | st lukes | St Lukes |
839
+ | St. Luke's Hospital | luk:hosp | Lukes Hosp |
840
+ | St. Luke's Hospital | st:spital | nil |
841
+ | St. Luke's Hospital | uk spital | ukes Hospital |
842
+ | St. Luke's Hospital | st:laks | nil |
843
+ | St. Luke's Hospital | :lukes | nil |
844
+ | St. Luke's Hospital | s lukes | St Lukes |
845
+ | St. Luke's Hospital | lukes:hospital | Lukes Hospital |
846
+ #+end_example
847
+
848
+ **** Method ~#matches_with~
849
+ The ~#matches_with(matcher)~ method allows the use of either a regular
850
+ expression or fuzzy matching as described above depending on whether the
851
+ matcher is enclosed in '/' characters. It also returns the matched portion of
852
+ ~self~ or nil if there is no match. Even when a regex is given, the match is
853
+ case insensitive by default and commas, apostrophes, and periods are removed
854
+ from the subject string before matching.
855
+
856
+ #+begin_src ruby
857
+ require_relative './lib/fat_core/string'
858
+
859
+ result = []
860
+ result << ['Self', 'Matcher', 'Match']
861
+ result << nil
862
+ subj = "St. Luke's Hospital"
863
+ matchers = ['st lukes', '/luk.*hosp/', 'st:spital', '/u.*s\b/', 'st:laks', ':lukes', 's lukes', '/lukes hospital\z/']
864
+ matchers.each do |m|
865
+ result << [subj, m, subj.matches_with(m)]
866
+ end
867
+ result
868
+ #+end_src
869
+
870
+ #+begin_example
871
+ | Self | Matcher | Match |
872
+ |---------------------+--------------------+----------------|
873
+ | St. Luke's Hospital | st lukes | St Lukes |
874
+ | St. Luke's Hospital | /luk.*hosp/ | Lukes Hosp |
875
+ | St. Luke's Hospital | st:spital | nil |
876
+ | St. Luke's Hospital | /u.*s\b/ | ukes |
877
+ | St. Luke's Hospital | st:laks | nil |
878
+ | St. Luke's Hospital | :lukes | nil |
879
+ | St. Luke's Hospital | s lukes | St Lukes |
880
+ | St. Luke's Hospital | /lukes hospital\z/ | Lukes Hospital |
881
+ #+end_example
882
+
883
+ **** Method ~#entitle~
884
+ For a string meant to serve as the title of a book, song, or other item, there
885
+ are certain rules in English as to which words should be capitalized and which
886
+ should be put in lower case. "PROFILES IN courage" should be rendered
887
+ "Profiles in Courage" for example. The preposition "in" is typically not
888
+ capitalized unless it starts the title: "in the HEAT OF THE NIght" should be
889
+ something like "In the Heat of the Night".
890
+
891
+ #+begin_src ruby
892
+ require_relative './lib/fat_core/string'
893
+
894
+ result = []
895
+ result << ['Self', 'Entitled']
896
+ result << nil
897
+ titles = ['PROFILES IN courage', 'in the HEAT OF THE NIght', 'a day in the life', 'FROM HERE TO ETERNITY',
898
+ 'lucy in the sky with diamonds']
899
+ titles.each do |t|
900
+ result << [t, t.entitle]
901
+ end
902
+ result
903
+ #+end_src
904
+
905
+ #+begin_example
906
+ | Self | Entitled |
907
+ |-------------------------------+-------------------------------|
908
+ | PROFILES IN courage | Profiles in Courage |
909
+ | in the HEAT OF THE NIght | In the Heat of the Night |
910
+ | a day in the life | A Day in the Life |
911
+ | FROM HERE TO ETERNITY | From Here to Eternity |
912
+ | lucy in the sky with diamonds | Lucy in the Sky With Diamonds |
913
+ #+end_example
914
+
915
+
916
+ **** Method ~#distance~
917
+ ~FatCore~ provides ~distance~ as a simple wrapper around the
918
+ Damerau-Levenshtein distance function in ~damerau-levenshtein~ gem, using a
919
+ block size of 1 and a max distance of 10.
920
+
921
+ #+begin_src ruby
922
+ require_relative './lib/fat_core/string'
923
+
924
+ result = []
925
+ result << ['Word1', 'Word2', 'Distance']
926
+ result << nil
927
+ pairs = [['Shelf', 'Shell'], ['Shelf', 'Shall'], ['Doherty', 'Daughtery'], ['Doherty', 'Dorrit'], ['Smith', 'Jones']]
928
+ pairs.each do |w1, w2|
929
+ result << [w1, w2, w1.distance(w2)]
930
+ end
931
+ result
932
+ #+end_src
933
+
934
+ #+begin_example
935
+ | Word1 | Word2 | Distance |
936
+ |---------+-----------+----------|
937
+ | Shelf | Shell | 1 |
938
+ | Shelf | Shall | 2 |
939
+ | Doherty | Daughtery | 5 |
940
+ | Doherty | Dorrit | 4 |
941
+ | Smith | Jones | 5 |
942
+ #+end_example
943
+
944
+ **** Method ~#commas(places)~
945
+ When presenting numbers, it is common to want to add grouping digits to make
946
+ the numbers more readable. The ~commas(places)~ method does this be
947
+ converting the number into a Float, rounding to places digits, then converting
948
+ back to a ~String~ with grouping commas inserted.
949
+
950
+ #+begin_src ruby
951
+ require_relative './lib/fat_core/string'
952
+
953
+ result = []
954
+ result << ['N', 'Places', 'With Commas']
955
+ result << nil
956
+ nums_places = [["798964655.66541325", 3], ["798964655.66541325", 0], ["798964655.66541325", 5], ["3.14159", 3],
957
+ ["3.14159e6", 3], ["-3.14159e4", 2], ["+3.14159e3", 2]]
958
+ nums_places.each do |n, p|
959
+ result << [n, p, n.commas(p)]
960
+ end
961
+ result
962
+ #+end_src
963
+
964
+ #+begin_example
965
+ | N | Places | With Commas |
966
+ |--------------------+--------+-------------------|
967
+ | 798964655.66541325 | 3 | 798,964,655.665 |
968
+ | 798964655.66541325 | 0 | 798,964,656 |
969
+ | 798964655.66541325 | 5 | 798,964,655.66541 |
970
+ | 3.14159 | 3 | 3.142 |
971
+ | 3.14159e6 | 3 | 3,141,590.000 |
972
+ | -3.14159e4 | 2 | -31,415.90 |
973
+ | +3.14159e3 | 2 | 3,141.59 |
974
+ #+end_example
975
+
976
+
977
+ **** Method =#wrap(width, hang)=
978
+ This method wraps the string to a given width with an optional hanging indent
979
+ for lines after the first.
980
+ #+begin_src ruby
981
+ require_relative './lib/fat_core/string'
982
+
983
+ getty = <<~EOS
984
+ Four score and seven years ago our fathers brought forth on this continent,
985
+ a new nation, conceived in Liberty, and dedicated to the proposition that
986
+ all men are created equal.
987
+
988
+ Now we are engaged in a great civil war, testing whether that nation, or any
989
+ nation so conceived and so dedicated, can long endure. We are met on a
990
+ great battle-field of that war. We have come to dedicate a portion of that
991
+ field, as a final resting place for those who here gave their lives that
992
+ that nation might live. It is altogether fitting and proper that we should
993
+ do this.
994
+
995
+ But, in a larger sense, we can not dedicate---we can not consecrate---we can
996
+ not hallow---this ground. The brave men, living and dead, who struggled
997
+ here, have consecrated it, far above our poor power to add or detract. The
998
+ world will little note, nor long remember what we say here, but it can never
999
+ forget what they did here. It is for us the living, rather, to be dedicated
1000
+ here to the unfinished work which they who fought here have thus far so
1001
+ nobly advanced. It is rather for us to be here dedicated to the great task
1002
+ remaining before us---that from these honored dead we take increased
1003
+ devotion to that cause for which they gave the last full measure of
1004
+ devotion---that we here highly resolve that these dead shall not have died
1005
+ in vain---that this nation, under God, shall have a new birth of
1006
+ freedom---and that government of the people, by the people, for the people,
1007
+ shall not perish from the earth.
1008
+ EOS
1009
+ getty.wrap(110, 3)
1010
+ #+end_src
1011
+
1012
+ #+begin_example
1013
+ Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived
1014
+ in Liberty, and dedicated to the proposition that all men are created equal. Now we are engaged
1015
+ in a great civil war, testing whether that nation, or any nation so conceived and so dedicated,
1016
+ can long endure. We are met on a great battle-field of that war. We have come to dedicate
1017
+ a portion of that field, as a final resting place for those who here gave their lives that
1018
+ that nation might live. It is altogether fitting and proper that we should do this. But, in
1019
+ a larger sense, we can not dedicate---we can not consecrate---we can not hallow---this ground.
1020
+ The brave men, living and dead, who struggled here, have consecrated it, far above our poor
1021
+ power to add or detract. The world will little note, nor long remember what we say here, but
1022
+ it can never forget what they did here. It is for us the living, rather, to be dedicated here
1023
+ to the unfinished work which they who fought here have thus far so nobly advanced. It is rather
1024
+ for us to be here dedicated to the great task remaining before us---that from these honored
1025
+ dead we take increased devotion to that cause for which they gave the last full measure of
1026
+ devotion---that we here highly resolve that these dead shall not have died in vain---that this
1027
+ nation, under God, shall have a new birth of freedom---and that government of the people, by
1028
+ the people, for the people, shall not perish from the earth.
1029
+ #+end_example
1030
+
1031
+ **** Method =#as_sym=
1032
+ Convert a ~String~ to a ~Symbol~ by converting all letters to lower-case,
1033
+ replacing hyphens and white space with a single underscore, and removing all
1034
+ non-alphanumeric characters:
1035
+
1036
+ #+begin_src ruby
1037
+ require_relative './lib/fat_core/string'
1038
+
1039
+ " Hello-to-the World!!!".as_sym
1040
+ #+end_src
1041
+
1042
+ #+begin_example
1043
+ :hello_to_the_world
1044
+ #+end_example
1045
+
1046
+ *** Symbol
1047
+ **** Method =#as_str=
1048
+ A quasi-inverse of ~String#as_sym~, convert a ~Symbol~ into a ~String~ by
1049
+ converting '_' to a hyphen, white-space into '_', and eliminate any
1050
+ non-alphanumeric characters.
1051
+
1052
+ #+begin_src ruby
1053
+ require_relative 'lib/fat_core/symbol'
1054
+
1055
+ :hello_to_the_world.as_str
1056
+ #+end_src
1057
+
1058
+ #+begin_example
1059
+ hello-to-the-world
1060
+ #+end_example
1061
+
512
1062
  *** TeX Quoting
1063
+ The extensions for ~String~, ~Numeric~, ~Range~, ~Symbol~, and ~NilClass~
1064
+ provide a ~#tex_quote~ method for quoting the string version of an object so
1065
+ as to allow its inclusion in a TeX document while quoting characters such as
1066
+ '_', $' or '%' that have a special meaning for TeX. At the same time it
1067
+ deploys TeX notation when special notation is available, for example, a
1068
+ ~Rational~ is rendered as a fraction.
513
1069
 
514
- Several of the extension, most notably 'fat_core/string', provides a
515
- ~#tex_quote~ method for quoting the string version of an object so as to allow
516
- its inclusion in a TeX document and quote characters such as '$' or '%' that
517
- have a special meaning for TeX.
1070
+ #+begin_src ruby
1071
+ require_relative 'lib/fat_core/all'
1072
+ require 'date'
1073
+
1074
+ result = []
1075
+ result << ['Class', 'Example', '#tex_quote']
1076
+ result << nil
1077
+ examples = [
1078
+ "Save $100 or 14% on this Friday_Black",
1079
+ 58743.44,
1080
+ Float::INFINITY,
1081
+ Math::PI,
1082
+ Complex(5, 3),
1083
+ Complex(5.0, 3.0),
1084
+ Rational(5, 3),
1085
+ Rational(8.0, 17.0),
1086
+ (Date.parse('2020-09-22')..Date.today),
1087
+ (Math::E..Math::PI),
1088
+ :four_score_and_7_years,
1089
+ nil
1090
+ ]
1091
+ examples.each do |ex|
1092
+ result << [ex.class, ex.to_s, ex.tex_quote.inspect]
1093
+ end
1094
+ result
1095
+ #+end_src
518
1096
 
519
- *** Numbers
1097
+ #+begin_example
1098
+ | Class | Example | #tex_quote |
1099
+ |----------+---------------------------------------+-----------------------------------------------|
1100
+ | String | Save $100 or 14% on this Friday_Black | "Save \\$100 or 14\\% on this Friday\\_Black" |
1101
+ | Float | 58743.44 | "58743.44" |
1102
+ | Float | Infinity | "$\\infty$" |
1103
+ | Float | 3.141592653589793 | "$\\pi$" |
1104
+ | Complex | 5+3i | "$5+3i$" |
1105
+ | Complex | 5.0+3.0i | "$5+3i$" |
1106
+ | Rational | 5/3 | "$\\frac{5}{3}$" |
1107
+ | Rational | 8/17 | "$\\frac{8}{17}$" |
1108
+ | Range | 2020-09-22..2025-11-24 | "(2020-09-22..2025-11-24)" |
1109
+ | Range | 2.718281828459045..3.141592653589793 | "($e$..$\\pi$)" |
1110
+ | Symbol | four_score_and_7_years | "four\\_score\\_and\\_7\\_years" |
1111
+ | NilClass | | "" |
1112
+ #+end_example
520
1113
 
521
- FatCore::Numeric has methods for inserting grouping commas into a number
522
- (~#commas~ and ~#group~), for converting seconds to HH:MM:SS.dd format
523
- (~#secs_to_hms~), for testing for integrality (~#whole?~ and ~#int_if_whole~), and
524
- testing for sign (~#signum~).
525
1114
 
526
- ** Contributing
1115
+ * Contributing
527
1116
 
528
1117
  1. Fork it ([[http://github.com/ddoherty03/fat_core/fork]] )
529
1118
  2. Create your feature branch (~git checkout -b my-new-feature~)