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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +54 -0
- data/.rubocop.yml +4 -6
- data/.simplecov +2 -0
- data/CHANGELOG.org +49 -0
- data/Gemfile +5 -4
- data/README.org +1016 -427
- data/Rakefile +15 -2
- data/bin/console +2 -3
- data/fat_core.gemspec +1 -0
- data/lib/fat_core/all.rb +9 -11
- data/lib/fat_core/array.rb +5 -5
- data/lib/fat_core/enumerable.rb +0 -15
- data/lib/fat_core/hash.rb +48 -11
- data/lib/fat_core/numeric.rb +48 -1
- data/lib/fat_core/range.rb +108 -55
- data/lib/fat_core/string.rb +70 -57
- data/lib/fat_core/symbol.rb +1 -1
- data/lib/fat_core/version.rb +2 -2
- data/lib/fat_core.rb +2 -2
- data/spec/lib/array_spec.rb +2 -0
- data/spec/lib/big_decimal_spec.rb +2 -0
- data/spec/lib/enumerable_spec.rb +29 -39
- data/spec/lib/hash_spec.rb +19 -2
- data/spec/lib/nil_class_spec.rb +2 -0
- data/spec/lib/numeric_spec.rb +14 -0
- data/spec/lib/range_spec.rb +101 -90
- data/spec/lib/string_spec.rb +78 -20
- data/spec/lib/symbol_spec.rb +2 -0
- data/spec/spec_helper.rb +3 -1
- metadata +9 -10
- data/bin/easter +0 -45
- data/lib/fat_core/date.rb +0 -1897
- data/lib/fat_core/kernel.rb +0 -26
- data/spec/lib/date_spec.rb +0 -1390
- data/spec/lib/kernel_spec.rb +0 -13
data/lib/fat_core/string.rb
CHANGED
|
@@ -93,26 +93,6 @@ module FatCore
|
|
|
93
93
|
r.gsub('XzXzXcbXzXzX', '\\}')
|
|
94
94
|
end
|
|
95
95
|
|
|
96
|
-
# Convert a string representing a date with only digits, hyphens, or slashes
|
|
97
|
-
# to a Date.
|
|
98
|
-
#
|
|
99
|
-
# @example
|
|
100
|
-
# "20090923".as_date.iso -> "2009-09-23"
|
|
101
|
-
# "2009/09/23".as_date.iso -> "2009-09-23"
|
|
102
|
-
# "2009-09-23".as_date.iso -> "2009-09-23"
|
|
103
|
-
# "2009-9-23".as_date.iso -> "2009-09-23"
|
|
104
|
-
#
|
|
105
|
-
# @return [Date] the translated Date
|
|
106
|
-
def as_date
|
|
107
|
-
if self =~ %r{(?<yr>\d\d\d\d)[-/]?(?<mo>\d\d?)[-/]?(?<dy>\d\d?)}
|
|
108
|
-
::Date.new(
|
|
109
|
-
Regexp.last_match[:yr].to_i,
|
|
110
|
-
Regexp.last_match[:mo].to_i,
|
|
111
|
-
Regexp.last_match[:dy].to_i,
|
|
112
|
-
)
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
|
|
116
96
|
UPPERS = ('A'..'Z').to_a
|
|
117
97
|
REGEXP_META_CHARACTERS = "\\$()*+.<>?[]^{|}".chars.freeze
|
|
118
98
|
|
|
@@ -153,18 +133,15 @@ module FatCore
|
|
|
153
133
|
a
|
|
154
134
|
an
|
|
155
135
|
the
|
|
156
|
-
at
|
|
157
|
-
for
|
|
158
|
-
up
|
|
159
136
|
and
|
|
160
137
|
but
|
|
161
138
|
or
|
|
162
139
|
nor
|
|
140
|
+
at
|
|
141
|
+
for
|
|
163
142
|
in
|
|
164
143
|
on
|
|
165
|
-
under
|
|
166
144
|
of
|
|
167
|
-
from
|
|
168
145
|
as
|
|
169
146
|
by
|
|
170
147
|
to
|
|
@@ -199,10 +176,13 @@ module FatCore
|
|
|
199
176
|
elsif /^(N|S|E|W|NE|NW|SE|SW)$/i.match?(w)
|
|
200
177
|
# Compass directions all caps
|
|
201
178
|
newwords.push(w.upcase)
|
|
179
|
+
elsif little_words.include?(w.downcase)
|
|
180
|
+
# Only capitalize at beginning or end
|
|
181
|
+
newwords.push(first || last ? w.capitalize : w.downcase)
|
|
202
182
|
elsif w =~ /^[^aeiouy]*$/i && w.size > 2
|
|
203
183
|
# All consonants and at least 3 chars, probably abbr
|
|
204
184
|
newwords.push(w.upcase)
|
|
205
|
-
elsif w =~ /^[A-Z0-9]+\z/ && preserve_acronyms
|
|
185
|
+
elsif w =~ /[0-9]/ && w =~ /^[A-Z0-9]+\z/ && w.size <= 5 && preserve_acronyms
|
|
206
186
|
# All uppercase and numbers, keep as is
|
|
207
187
|
newwords.push(w)
|
|
208
188
|
elsif w =~ /^(\w+)-(\w+)$/i
|
|
@@ -212,9 +192,6 @@ module FatCore
|
|
|
212
192
|
# Last word ended with a ':'
|
|
213
193
|
newwords.push(w.capitalize)
|
|
214
194
|
capitalize_next = false
|
|
215
|
-
elsif little_words.include?(w.downcase)
|
|
216
|
-
# Only capitalize at beginning or end
|
|
217
|
-
newwords.push(first || last ? w.capitalize : w.downcase)
|
|
218
195
|
else
|
|
219
196
|
# All else
|
|
220
197
|
newwords.push(w.capitalize)
|
|
@@ -249,11 +226,13 @@ module FatCore
|
|
|
249
226
|
# @see #fuzzy_match #fuzzy_match for the specifics of string matching
|
|
250
227
|
# @see #as_regexp #as_regexp for conversion of `matcher` to regular expression
|
|
251
228
|
def matches_with(matcher)
|
|
229
|
+
target = clean.gsub(/[\*.,']/, '')
|
|
252
230
|
if matcher.nil?
|
|
253
231
|
nil
|
|
254
|
-
elsif matcher
|
|
232
|
+
elsif matcher.match?(%r{^\s*/})
|
|
255
233
|
re = matcher.as_regexp
|
|
256
|
-
|
|
234
|
+
md = target.match(re)
|
|
235
|
+
md[0] if md
|
|
257
236
|
else
|
|
258
237
|
to_s.fuzzy_match(matcher)
|
|
259
238
|
end
|
|
@@ -262,22 +241,32 @@ module FatCore
|
|
|
262
241
|
# Return the matched portion of self, minus punctuation characters, if self
|
|
263
242
|
# matches the string `matcher` using the following notion of matching:
|
|
264
243
|
#
|
|
265
|
-
# 1. Remove
|
|
266
|
-
#
|
|
267
|
-
# 2.
|
|
268
|
-
#
|
|
244
|
+
# 1. Remove leading and trailing whitespace in the subject and the matcher
|
|
245
|
+
# and collapse its internal whitespace to a single space,
|
|
246
|
+
# 2. Remove all periods, commas, apostrophes, and asterisks (the
|
|
247
|
+
# punctuation characters) from both self and `matcher`,
|
|
248
|
+
# 3. Treat internal ':stuff' or ' :stuff' in the matcher as the equivalent
|
|
249
|
+
# of /\bstuff.*/ in a regular expression, that is, match any word
|
|
269
250
|
# starting with stuff in self,
|
|
270
|
-
#
|
|
251
|
+
# 4. Treat internal 'stuff: ' in the matcher as the equivalent
|
|
252
|
+
# of /.*stuff\b/ in a regular expression, that is, match any word
|
|
253
|
+
# ending with stuff in self,
|
|
254
|
+
# 5. A colon with no spaces around it is treated as belonging to the
|
|
255
|
+
# following word, requiring it to start with it, so 'some:stuff'
|
|
256
|
+
# requires 'some' anywhere followed by a word beginning with 'stuff',
|
|
257
|
+
# i.e., /some.*\bstuff/i,
|
|
258
|
+
# 6. Treat leading ':' in the matcher as anchoring the match to the
|
|
271
259
|
# beginning of the target string,
|
|
272
|
-
#
|
|
260
|
+
# 7. Treat ending ':' in the matcher as anchoring the match to the
|
|
273
261
|
# end of the target string,
|
|
274
|
-
#
|
|
275
|
-
#
|
|
262
|
+
# 8. Require each component to match some part of self, and
|
|
263
|
+
# 9. Ignore case in the match
|
|
276
264
|
#
|
|
277
265
|
# @example
|
|
278
266
|
# "St. Luke's Hospital".fuzzy_match('st lukes') #=> 'St Lukes'
|
|
279
267
|
# "St. Luke's Hospital".fuzzy_match('luk:hosp') #=> 'Lukes Hosp'
|
|
280
|
-
# "St. Luke's Hospital".fuzzy_match('st:spital') #=>
|
|
268
|
+
# "St. Luke's Hospital".fuzzy_match('st:spital') #=> nil
|
|
269
|
+
# "St. Luke's Hospital".fuzzy_match('st spital') #=> 'St Lukes Hospital'
|
|
281
270
|
# "St. Luke's Hospital".fuzzy_match('st:laks') #=> nil
|
|
282
271
|
# "St. Luke's Hospital".fuzzy_match(':lukes') #=> nil
|
|
283
272
|
# "St. Luke's Hospital".fuzzy_match('lukes:hospital:') #=> 'Lukes Hospital'
|
|
@@ -287,22 +276,16 @@ module FatCore
|
|
|
287
276
|
# @return [nil] if self did not match matcher
|
|
288
277
|
def fuzzy_match(matcher)
|
|
289
278
|
# Remove periods, asterisks, commas, and apostrophes
|
|
290
|
-
matcher = matcher.strip.gsub(/[\*.,']/, '')
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
matcher.
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
matchers = matcher.split(/[: ]+/)
|
|
301
|
-
regexp_string = matchers.map { |m| ".*?\\b#{Regexp.escape(m)}.*?" }.join('\\b')
|
|
302
|
-
regexp_string.sub!(/^\.\*\?/, '')
|
|
303
|
-
regexp_string.sub!(/\.\*\?$/, '')
|
|
304
|
-
regexp_string.sub!(/\A/, '\\A') if begin_anchor
|
|
305
|
-
regexp_string.sub!(/\z/, '\\z') if end_anchor
|
|
279
|
+
matcher = matcher.clean.strip.gsub(/[\*.,']/, '')
|
|
280
|
+
target = clean.gsub(/[\*.,']/, '')
|
|
281
|
+
regexp_string =
|
|
282
|
+
if matcher.match?(/[: ]/)
|
|
283
|
+
matcher.sub(/\A:/, "\\A").sub(/:\z/, "\\z")
|
|
284
|
+
.gsub(/:\s+/, "\\b.*").gsub(':', ".*\\b")
|
|
285
|
+
.gsub(/\s+/, ".*")
|
|
286
|
+
else
|
|
287
|
+
Regexp.escape(matcher)
|
|
288
|
+
end
|
|
306
289
|
regexp = /#{regexp_string}/i
|
|
307
290
|
matched_text =
|
|
308
291
|
if (match = regexp.match(target))
|
|
@@ -337,7 +320,6 @@ module FatCore
|
|
|
337
320
|
flags |= Regexp::MULTILINE if opts.include?('m')
|
|
338
321
|
end
|
|
339
322
|
flags = nil if flags.zero?
|
|
340
|
-
# body = Regexp.quote(body) if REGEXP_META_CHARACTERS.include?(body)
|
|
341
323
|
Regexp.new(body, flags)
|
|
342
324
|
else
|
|
343
325
|
Regexp.new(Regexp.quote(self), Regexp::IGNORECASE)
|
|
@@ -408,3 +390,34 @@ class String
|
|
|
408
390
|
# @!parse include FatCore::String
|
|
409
391
|
# @!parse extend FatCore::String::ClassMethods
|
|
410
392
|
end
|
|
393
|
+
|
|
394
|
+
module StringPred
|
|
395
|
+
refine String do
|
|
396
|
+
# This is a kludgy version of #pred (Ruby does define it for a good
|
|
397
|
+
# reason, namely there is no unique string for which x.pred.succ == x).
|
|
398
|
+
# Still, for my Range extensions, it helps to have this limited version to
|
|
399
|
+
# produce a usable #pred for the #gaps method.
|
|
400
|
+
def pred
|
|
401
|
+
str = clean
|
|
402
|
+
return "9" if str.length == 1 && str[0] == 'A'
|
|
403
|
+
return "Z" if str.length == 1 && str[0] == 'a'
|
|
404
|
+
return "a" if str.length == 1 && str[0] == '0'
|
|
405
|
+
return "" if str.empty?
|
|
406
|
+
|
|
407
|
+
unless str.match?(/\A[A-Za-z0-9]+\z/)
|
|
408
|
+
raise NoMethodError, "undefined method :pred for \"#{self}\":String"
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
case str[-1]
|
|
412
|
+
when 'A'
|
|
413
|
+
str[0..-2].pred + 'Z'
|
|
414
|
+
when 'a'
|
|
415
|
+
str[0..-2].pred + 'z'
|
|
416
|
+
when '0'
|
|
417
|
+
str[0..-2].pred + '9'
|
|
418
|
+
else
|
|
419
|
+
str[0..-2] + (str[-1].ord - 1).chr
|
|
420
|
+
end
|
|
421
|
+
end
|
|
422
|
+
end
|
|
423
|
+
end
|
data/lib/fat_core/symbol.rb
CHANGED
data/lib/fat_core/version.rb
CHANGED
data/lib/fat_core.rb
CHANGED
data/spec/lib/array_spec.rb
CHANGED
data/spec/lib/enumerable_spec.rb
CHANGED
|
@@ -1,51 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'spec_helper'
|
|
2
4
|
require 'fat_core/enumerable'
|
|
3
5
|
|
|
4
6
|
describe Enumerable do
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
describe '#each_with_flags' do
|
|
8
|
+
it 'enumerates each with first and last flags' do
|
|
9
|
+
letters = ('a'..'z').to_a
|
|
10
|
+
letters.each_with_flags do |l, first, last|
|
|
11
|
+
if l == 'a'
|
|
12
|
+
expect(first).to be true
|
|
13
|
+
expect(last).to be false
|
|
14
|
+
elsif l == 'z'
|
|
15
|
+
expect(first).to be false
|
|
16
|
+
expect(last).to be true
|
|
17
|
+
else
|
|
18
|
+
expect(first).to be false
|
|
19
|
+
expect(last).to be false
|
|
20
|
+
end
|
|
15
21
|
end
|
|
16
22
|
end
|
|
17
|
-
end
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
expect(first).to be true
|
|
24
|
-
expect(last).to be false
|
|
25
|
-
elsif l == 'z'
|
|
26
|
-
expect(first).to be false
|
|
27
|
-
expect(last).to be true
|
|
28
|
-
else
|
|
29
|
-
expect(first).to be false
|
|
30
|
-
expect(last).to be false
|
|
31
|
-
end
|
|
24
|
+
it 'returns nil enumerating a beginless Range' do
|
|
25
|
+
bless = (..100)
|
|
26
|
+
result = bless.each_with_flags { |_l, _first, _last| 44 }
|
|
27
|
+
expect(result).to be_nil
|
|
32
28
|
end
|
|
33
|
-
end
|
|
34
29
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
eless.each_with_flags do |i, _first, _last|
|
|
45
|
-
num += i
|
|
46
|
-
break if i >= 100
|
|
30
|
+
it 'enumerates an endless Range' do
|
|
31
|
+
eless = (1..)
|
|
32
|
+
num = 0
|
|
33
|
+
eless.each_with_flags do |i, _first, _last|
|
|
34
|
+
num += i
|
|
35
|
+
break if i >= 100
|
|
36
|
+
end
|
|
37
|
+
# Look at me, I'm Gauss
|
|
38
|
+
expect(num).to eq(5050)
|
|
47
39
|
end
|
|
48
|
-
# Look at me, I'm Gauss
|
|
49
|
-
expect(num).to eq(5050)
|
|
50
40
|
end
|
|
51
41
|
end
|
data/spec/lib/hash_spec.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'spec_helper'
|
|
2
4
|
require 'fat_core/hash'
|
|
3
5
|
|
|
@@ -10,8 +12,8 @@ describe Hash do
|
|
|
10
12
|
|
|
11
13
|
it 'deletes entries with a value == to X' do
|
|
12
14
|
hh = { :a => 1, :b => 2, :c => 1 }
|
|
13
|
-
expect(hh.delete_with_value(1)).to eq({ :b => 2 })
|
|
14
|
-
expect(hh.delete_with_value(9)).to eq hh
|
|
15
|
+
expect(hh.delete_with_value!(1)).to eq({ :b => 2 })
|
|
16
|
+
expect(hh.delete_with_value!(9)).to eq hh
|
|
15
17
|
end
|
|
16
18
|
|
|
17
19
|
it 'maps keys to new keys' do
|
|
@@ -29,4 +31,19 @@ describe Hash do
|
|
|
29
31
|
h3 = { e: 'EEE' }
|
|
30
32
|
expect(h1 << h2 << h3).to eq({ a: 'A', b: 'BB', c: 'C', d: 'DD', e: 'EEE' })
|
|
31
33
|
end
|
|
34
|
+
|
|
35
|
+
it 'can take any Enumerable as a right argument' do
|
|
36
|
+
FileUtils.mkdir_p('./tmp')
|
|
37
|
+
ff = File.open('./tmp/junk', 'w')
|
|
38
|
+
ff.write("f\n", "FFFF\n", "g\n", "GGGG\n")
|
|
39
|
+
ff.close
|
|
40
|
+
ff = File.open('./tmp/junk', 'r')
|
|
41
|
+
h = { a: 'A', b: 'B', c: 'C' } << [:c, 'CC', :d, 'DD'] <<
|
|
42
|
+
{ d: 'DDD', e: 'EEE' } <<
|
|
43
|
+
ff.readlines.map(&:chomp)
|
|
44
|
+
h.transform_keys!(&:to_sym)
|
|
45
|
+
ff.close
|
|
46
|
+
expect(h.keys).to include(:a, :b, :c, :d, :e, :f, :g)
|
|
47
|
+
FileUtils.rm_rf('./tmp/junk')
|
|
48
|
+
end
|
|
32
49
|
end
|
data/spec/lib/nil_class_spec.rb
CHANGED
data/spec/lib/numeric_spec.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'spec_helper'
|
|
2
4
|
require 'fat_core/numeric'
|
|
3
5
|
|
|
@@ -16,6 +18,18 @@ describe Numeric do
|
|
|
16
18
|
|
|
17
19
|
it 'provides a tex_quote method for erb docs' do
|
|
18
20
|
expect(195.45.tex_quote).to eq '195.45'
|
|
21
|
+
expect(195.00.tex_quote).to eq '195.0'
|
|
22
|
+
expect(58743.44.tex_quote).to eq '58743.44'
|
|
23
|
+
expect(Float::INFINITY.tex_quote).to eq("$\\infty$")
|
|
24
|
+
expect((-Float::INFINITY).tex_quote).to eq("$-\\infty$")
|
|
25
|
+
expect(Complex(5, 3).tex_quote).to eq("$5+3i$")
|
|
26
|
+
expect(Complex(7, 1).tex_quote).to eq("$7+i$")
|
|
27
|
+
expect(Complex(7.00, 1).tex_quote).to eq("$7+i$")
|
|
28
|
+
expect(Complex(Math::PI, 1).tex_quote).to eq("$\\pi+i$")
|
|
29
|
+
expect(Complex(Math::E, 1).tex_quote).to eq("$e+i$")
|
|
30
|
+
expect(Complex(Math::E, Math::PI).tex_quote).to eq("$e+\\pi i$")
|
|
31
|
+
expect(Complex(Math::PI, Math::E).tex_quote).to eq("$\\pi+e i$")
|
|
32
|
+
expect(Rational(5, 3).tex_quote).to eq("$\\frac{5}{3}$")
|
|
19
33
|
end
|
|
20
34
|
|
|
21
35
|
it 'knows if its a whole number' do
|