fat_core 6.0.0 → 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 -2
- data/.simplecov +2 -0
- data/CHANGELOG.org +49 -0
- data/Gemfile +5 -4
- data/README.org +1018 -58
- data/Rakefile +15 -2
- data/bin/console +1 -0
- data/fat_core.gemspec +1 -0
- data/lib/fat_core/all.rb +9 -10
- 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 -37
- data/lib/fat_core/symbol.rb +1 -1
- data/lib/fat_core/version.rb +2 -2
- data/lib/fat_core.rb +2 -0
- 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 +10 -0
- data/spec/lib/string_spec.rb +78 -11
- data/spec/lib/symbol_spec.rb +2 -0
- data/spec/spec_helper.rb +3 -1
- metadata +8 -5
- data/lib/fat_core/kernel.rb +0 -26
- data/spec/lib/kernel_spec.rb +0 -13
data/lib/fat_core/string.rb
CHANGED
|
@@ -133,18 +133,15 @@ module FatCore
|
|
|
133
133
|
a
|
|
134
134
|
an
|
|
135
135
|
the
|
|
136
|
-
at
|
|
137
|
-
for
|
|
138
|
-
up
|
|
139
136
|
and
|
|
140
137
|
but
|
|
141
138
|
or
|
|
142
139
|
nor
|
|
140
|
+
at
|
|
141
|
+
for
|
|
143
142
|
in
|
|
144
143
|
on
|
|
145
|
-
under
|
|
146
144
|
of
|
|
147
|
-
from
|
|
148
145
|
as
|
|
149
146
|
by
|
|
150
147
|
to
|
|
@@ -179,10 +176,13 @@ module FatCore
|
|
|
179
176
|
elsif /^(N|S|E|W|NE|NW|SE|SW)$/i.match?(w)
|
|
180
177
|
# Compass directions all caps
|
|
181
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)
|
|
182
182
|
elsif w =~ /^[^aeiouy]*$/i && w.size > 2
|
|
183
183
|
# All consonants and at least 3 chars, probably abbr
|
|
184
184
|
newwords.push(w.upcase)
|
|
185
|
-
elsif w =~ /^[A-Z0-9]+\z/ && preserve_acronyms
|
|
185
|
+
elsif w =~ /[0-9]/ && w =~ /^[A-Z0-9]+\z/ && w.size <= 5 && preserve_acronyms
|
|
186
186
|
# All uppercase and numbers, keep as is
|
|
187
187
|
newwords.push(w)
|
|
188
188
|
elsif w =~ /^(\w+)-(\w+)$/i
|
|
@@ -192,9 +192,6 @@ module FatCore
|
|
|
192
192
|
# Last word ended with a ':'
|
|
193
193
|
newwords.push(w.capitalize)
|
|
194
194
|
capitalize_next = false
|
|
195
|
-
elsif little_words.include?(w.downcase)
|
|
196
|
-
# Only capitalize at beginning or end
|
|
197
|
-
newwords.push(first || last ? w.capitalize : w.downcase)
|
|
198
195
|
else
|
|
199
196
|
# All else
|
|
200
197
|
newwords.push(w.capitalize)
|
|
@@ -229,11 +226,13 @@ module FatCore
|
|
|
229
226
|
# @see #fuzzy_match #fuzzy_match for the specifics of string matching
|
|
230
227
|
# @see #as_regexp #as_regexp for conversion of `matcher` to regular expression
|
|
231
228
|
def matches_with(matcher)
|
|
229
|
+
target = clean.gsub(/[\*.,']/, '')
|
|
232
230
|
if matcher.nil?
|
|
233
231
|
nil
|
|
234
|
-
elsif matcher
|
|
232
|
+
elsif matcher.match?(%r{^\s*/})
|
|
235
233
|
re = matcher.as_regexp
|
|
236
|
-
|
|
234
|
+
md = target.match(re)
|
|
235
|
+
md[0] if md
|
|
237
236
|
else
|
|
238
237
|
to_s.fuzzy_match(matcher)
|
|
239
238
|
end
|
|
@@ -242,22 +241,32 @@ module FatCore
|
|
|
242
241
|
# Return the matched portion of self, minus punctuation characters, if self
|
|
243
242
|
# matches the string `matcher` using the following notion of matching:
|
|
244
243
|
#
|
|
245
|
-
# 1. Remove
|
|
246
|
-
#
|
|
247
|
-
# 2.
|
|
248
|
-
#
|
|
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
|
|
249
250
|
# starting with stuff in self,
|
|
250
|
-
#
|
|
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
|
|
251
259
|
# beginning of the target string,
|
|
252
|
-
#
|
|
260
|
+
# 7. Treat ending ':' in the matcher as anchoring the match to the
|
|
253
261
|
# end of the target string,
|
|
254
|
-
#
|
|
255
|
-
#
|
|
262
|
+
# 8. Require each component to match some part of self, and
|
|
263
|
+
# 9. Ignore case in the match
|
|
256
264
|
#
|
|
257
265
|
# @example
|
|
258
266
|
# "St. Luke's Hospital".fuzzy_match('st lukes') #=> 'St Lukes'
|
|
259
267
|
# "St. Luke's Hospital".fuzzy_match('luk:hosp') #=> 'Lukes Hosp'
|
|
260
|
-
# "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'
|
|
261
270
|
# "St. Luke's Hospital".fuzzy_match('st:laks') #=> nil
|
|
262
271
|
# "St. Luke's Hospital".fuzzy_match(':lukes') #=> nil
|
|
263
272
|
# "St. Luke's Hospital".fuzzy_match('lukes:hospital:') #=> 'Lukes Hospital'
|
|
@@ -267,22 +276,16 @@ module FatCore
|
|
|
267
276
|
# @return [nil] if self did not match matcher
|
|
268
277
|
def fuzzy_match(matcher)
|
|
269
278
|
# Remove periods, asterisks, commas, and apostrophes
|
|
270
|
-
matcher = matcher.strip.gsub(/[\*.,']/, '')
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
matcher.
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
matchers = matcher.split(/[: ]+/)
|
|
281
|
-
regexp_string = matchers.map { |m| ".*?\\b#{Regexp.escape(m)}.*?" }.join('\\b')
|
|
282
|
-
regexp_string.sub!(/^\.\*\?/, '')
|
|
283
|
-
regexp_string.sub!(/\.\*\?$/, '')
|
|
284
|
-
regexp_string.sub!(/\A/, '\\A') if begin_anchor
|
|
285
|
-
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
|
|
286
289
|
regexp = /#{regexp_string}/i
|
|
287
290
|
matched_text =
|
|
288
291
|
if (match = regexp.match(target))
|
|
@@ -317,7 +320,6 @@ module FatCore
|
|
|
317
320
|
flags |= Regexp::MULTILINE if opts.include?('m')
|
|
318
321
|
end
|
|
319
322
|
flags = nil if flags.zero?
|
|
320
|
-
# body = Regexp.quote(body) if REGEXP_META_CHARACTERS.include?(body)
|
|
321
323
|
Regexp.new(body, flags)
|
|
322
324
|
else
|
|
323
325
|
Regexp.new(Regexp.quote(self), Regexp::IGNORECASE)
|
|
@@ -388,3 +390,34 @@ class String
|
|
|
388
390
|
# @!parse include FatCore::String
|
|
389
391
|
# @!parse extend FatCore::String::ClassMethods
|
|
390
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
|
data/spec/lib/range_spec.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'spec_helper'
|
|
2
4
|
require 'fat_core/range'
|
|
3
5
|
|
|
@@ -206,6 +208,10 @@ describe Range do
|
|
|
206
208
|
expect(gaps[1]).to eq(7..8)
|
|
207
209
|
end
|
|
208
210
|
|
|
211
|
+
it 'returns gaps for letter ranges' do
|
|
212
|
+
expect(('a'..'z').gaps([('a'..'g'), ('j'..'s'), ('t'..'z')])).to eq([Range.new('h', 'i')])
|
|
213
|
+
end
|
|
214
|
+
|
|
209
215
|
it 'allows ranges to extend before and after self' do
|
|
210
216
|
gaps = (0..10).gaps([(-3..3), (4..6), (7..13)])
|
|
211
217
|
expect(gaps).to be_empty
|
|
@@ -244,6 +250,10 @@ describe Range do
|
|
|
244
250
|
gaps = (0..10).gaps([(-2..3), (2..8), (4..10)])
|
|
245
251
|
expect(gaps).to be_empty
|
|
246
252
|
end
|
|
253
|
+
|
|
254
|
+
it 'raises an error if argument types are incompatible' do
|
|
255
|
+
expect { ('A'..'F').gaps([(1..5), (6..11)]) }.to raise_error(/incompatible/)
|
|
256
|
+
end
|
|
247
257
|
end
|
|
248
258
|
|
|
249
259
|
describe '#overlaps' do
|
data/spec/lib/string_spec.rb
CHANGED
|
@@ -96,6 +96,22 @@ the people, for the people, shall not perish from the earth."
|
|
|
96
96
|
expect(' string here '.clean).to eq 'string here'
|
|
97
97
|
end
|
|
98
98
|
|
|
99
|
+
using StringPred
|
|
100
|
+
|
|
101
|
+
it 'computes predecessor to String' do
|
|
102
|
+
expect("B".pred).to eq("A")
|
|
103
|
+
expect("C".pred).to eq("B")
|
|
104
|
+
expect("D".pred).to eq("C")
|
|
105
|
+
expect("Z".pred).to eq("Y")
|
|
106
|
+
expect("AAA".pred).to eq("9ZZ")
|
|
107
|
+
expect("A".pred).to eq("9")
|
|
108
|
+
expect("BBA".pred).to eq("BAZ")
|
|
109
|
+
expect("00123".pred).to eq("00122")
|
|
110
|
+
expect("9999".succ).to eq("10000")
|
|
111
|
+
expect("00000".pred).to eq("a9999")
|
|
112
|
+
expect { "00123+".pred }.to raise_error(/undefined method/)
|
|
113
|
+
end
|
|
114
|
+
|
|
99
115
|
describe 'numeric strings' do
|
|
100
116
|
it 'converts a numeric string to a commified form' do
|
|
101
117
|
expect('20140521'.commas).to eq '20,140,521'
|
|
@@ -138,7 +154,6 @@ the people, for the people, shall not perish from the earth."
|
|
|
138
154
|
expect('-8.008'.number?).to be true
|
|
139
155
|
expect('8.008e33'.number?).to be true
|
|
140
156
|
expect('-8.008e33'.number?).to be true
|
|
141
|
-
expect('0x8.008').to be_number
|
|
142
157
|
expect('hello world'.number?).to be false
|
|
143
158
|
end
|
|
144
159
|
end
|
|
@@ -205,7 +220,7 @@ the people, for the people, shall not perish from the earth."
|
|
|
205
220
|
expect('tr'.entitle).to eq('Tr')
|
|
206
221
|
expect('trd'.entitle).to eq('TRD')
|
|
207
222
|
# Don't capitalize c/o
|
|
208
|
-
expect('
|
|
223
|
+
expect('sherLOCK c/o watson'.entitle).to eq('Sherlock c/o Watson')
|
|
209
224
|
# Capitlaize p.o.
|
|
210
225
|
expect('p.o. box 123'.entitle).to eq('P.O. Box 123')
|
|
211
226
|
# Don't capitalize ordinals
|
|
@@ -215,8 +230,6 @@ the people, for the people, shall not perish from the earth."
|
|
|
215
230
|
expect('nw territory'.entitle).to eq('NW Territory')
|
|
216
231
|
# Leave word starting with numbers alone
|
|
217
232
|
expect('apartment 33-B'.entitle).to eq('Apartment 33-B')
|
|
218
|
-
# Assume all uppercase is an acronym
|
|
219
|
-
expect('the ABC network'.entitle).to eq('The ABC Network')
|
|
220
233
|
# But not if the whole string is uppercase
|
|
221
234
|
expect('THE ABC NETWORK'.entitle).to eq('The Abc Network')
|
|
222
235
|
# Capitalize both parts of a hyphenated word
|
|
@@ -244,14 +257,10 @@ the people, for the people, shall not perish from the earth."
|
|
|
244
257
|
describe 'Fuzzy Matching' do
|
|
245
258
|
it 'fuzzy matches with another string' do
|
|
246
259
|
expect('Hello, world'.fuzzy_match('wor')).to be_truthy
|
|
260
|
+
expect('Hello, world'.fuzzy_match('orl')).to be_truthy
|
|
247
261
|
expect('Hello, world'.fuzzy_match('ox')).to be_falsy
|
|
248
262
|
end
|
|
249
263
|
|
|
250
|
-
it 'fuzzy matches with another string containing re' do
|
|
251
|
-
expect('Hello, world'.matches_with('/or/')).to be_truthy
|
|
252
|
-
expect('Hello, world'.matches_with('/ox/')).to be_falsy
|
|
253
|
-
end
|
|
254
|
-
|
|
255
264
|
it 'fuzzy matches space-separated parts' do
|
|
256
265
|
expect('Hello world'.fuzzy_match('hel wor')).to be_truthy
|
|
257
266
|
expect('Hello, world'.fuzzy_match('hel ox')).to be_falsy
|
|
@@ -259,22 +268,35 @@ the people, for the people, shall not perish from the earth."
|
|
|
259
268
|
|
|
260
269
|
it 'fuzzy matches colon-separated parts' do
|
|
261
270
|
expect('Hello:world'.fuzzy_match('hel:wor')).to be_truthy
|
|
262
|
-
expect('Hello:world'.fuzzy_match('hel:
|
|
271
|
+
expect('Hello:world'.fuzzy_match('hel :wor')).to be_truthy
|
|
272
|
+
expect('Hello:world'.fuzzy_match('hel: wor')).to be_falsy
|
|
273
|
+
expect('Hello:world'.fuzzy_match('hel:orld')).to be_falsy
|
|
274
|
+
expect("Hello, 'world'".fuzzy_match('hel:wor')).to be_truthy
|
|
275
|
+
expect('Hello "world"'.fuzzy_match('hel:world')).to be_truthy
|
|
263
276
|
end
|
|
264
277
|
|
|
265
|
-
it 'treats an internal `:stuff
|
|
278
|
+
it 'treats an internal `:stuff` as \bstuff.*' do
|
|
266
279
|
expect('Hello, what is with the world?'.fuzzy_match('wha:wi:wor')).to be_truthy
|
|
280
|
+
expect('Hello, what is with the world?'.fuzzy_match('hat :wi :wor')).to be_truthy
|
|
267
281
|
expect('Hello:world'.fuzzy_match('what:or')).to be_falsy
|
|
268
282
|
expect('Hello, what=+&is (with) the world?'.fuzzy_match('wha:wi:wor')).to be_truthy
|
|
269
283
|
end
|
|
270
284
|
|
|
285
|
+
it 'treats an internal `stuff: ` as stuff\b.*' do
|
|
286
|
+
expect('Hello, what is with the world?'.fuzzy_match('llo: th: :wor')).to be_truthy
|
|
287
|
+
expect('Hello:world'.fuzzy_match('llox: ')).to be_falsy
|
|
288
|
+
expect('Hello, what=+&is (with) the world?'.fuzzy_match('at: ith: the')).to be_truthy
|
|
289
|
+
end
|
|
290
|
+
|
|
271
291
|
it 'requires end-anchor for ending colon' do
|
|
272
292
|
expect('Hello, to the world'.fuzzy_match('hel:world:')).to eq('Hello to the world')
|
|
293
|
+
expect('Hello, to the world '.fuzzy_match('hel:world:')).to eq('Hello to the world')
|
|
273
294
|
expect('Hello, to the world today'.fuzzy_match('to:world:')).to be_nil
|
|
274
295
|
end
|
|
275
296
|
|
|
276
297
|
it 'requires start-anchor for leading colon' do
|
|
277
298
|
expect('Hello, to the world'.fuzzy_match(':hel:the')).to eq('Hello to the')
|
|
299
|
+
expect(' Hello, to the world'.fuzzy_match(':hel:the')).to eq('Hello to the')
|
|
278
300
|
expect('Hello, to the world today'.fuzzy_match(':world:today')).to be_nil
|
|
279
301
|
end
|
|
280
302
|
|
|
@@ -298,6 +320,51 @@ the people, for the people, shall not perish from the earth."
|
|
|
298
320
|
expect('The 1 Dollar Store'.fuzzy_match('1 stor')).to be_truthy
|
|
299
321
|
expect('The $1 Dollar Store'.fuzzy_match('$1 stor')).to be_falsy
|
|
300
322
|
end
|
|
323
|
+
|
|
324
|
+
it 'performs examples in documentation' do
|
|
325
|
+
expect("St. Luke's".fuzzy_match('st lukes')).to eq('St Lukes')
|
|
326
|
+
expect("St. Luke's Hospital".fuzzy_match('st lukes')).to eq('St Lukes')
|
|
327
|
+
expect("St. Luke's Hospital".fuzzy_match('luk:hosp')).to eq('Lukes Hosp')
|
|
328
|
+
expect("St. Luke's Hospital".fuzzy_match('st:spital')).to be_nil
|
|
329
|
+
expect("St. Luke's Hospital".fuzzy_match('st spital')).to eq('St Lukes Hospital')
|
|
330
|
+
expect("St. Luke's Hospital".fuzzy_match('st:laks')).to be_nil
|
|
331
|
+
expect("St. Luke's Hospital".fuzzy_match(':lukes')).to be_nil
|
|
332
|
+
expect("St. Luke's Hospital".fuzzy_match('lukes:hospital')).to eq('Lukes Hospital')
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
describe '#matches_with' do
|
|
337
|
+
it 'matches with another string containing a plain string' do
|
|
338
|
+
expect('Hello, world'.matches_with('or')).to be_truthy
|
|
339
|
+
expect('Hello, world'.matches_with('ox')).to be_falsy
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
it 'matches with another string containing re' do
|
|
343
|
+
expect('Hello, world'.matches_with('/or/')).to be_truthy
|
|
344
|
+
expect('Hello, world'.matches_with('/ox/')).to be_falsy
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
it 'performs examples in documentation with just strings' do
|
|
348
|
+
expect("St. Luke's".matches_with('st lukes')).to eq('St Lukes')
|
|
349
|
+
expect("St. Luke's Hospital".matches_with('st lukes')).to eq('St Lukes')
|
|
350
|
+
expect("St. Luke's Hospital".matches_with('luk:hosp')).to eq('Lukes Hosp')
|
|
351
|
+
expect("St. Luke's Hospital".matches_with('st:spital')).to be_nil
|
|
352
|
+
expect("St. Luke's Hospital".matches_with('st spital')).to eq('St Lukes Hospital')
|
|
353
|
+
expect("St. Luke's Hospital".matches_with('st:laks')).to be_nil
|
|
354
|
+
expect("St. Luke's Hospital".matches_with(':lukes')).to be_nil
|
|
355
|
+
expect("St. Luke's Hospital".matches_with('lukes:hospital')).to eq('Lukes Hospital')
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
it 'performs examples in documentation with regexes' do
|
|
359
|
+
expect("St. Luke's".matches_with('/st\s*lukes/')).to eq('St Lukes')
|
|
360
|
+
expect("St. Luke's Hospital".matches_with('/st lukes/')).to eq('St Lukes')
|
|
361
|
+
expect("St. Luke's Hospital".matches_with('/luk.*\bhosp/')).to eq('Lukes Hosp')
|
|
362
|
+
expect("St. Luke's Hospital".matches_with('/st(.*)spital\z/')).to eq('St Lukes Hospital')
|
|
363
|
+
expect("St. Luke's Hospital".matches_with('/st spital/')).to be_nil
|
|
364
|
+
expect("St. Luke's Hospital".matches_with('/st.*laks/')).to be_nil
|
|
365
|
+
expect("St. Luke's Hospital".matches_with('/\Alukes/')).to be_nil
|
|
366
|
+
expect("St. Luke's Hospital".matches_with('/lukes hospital/')).to eq('Lukes Hospital')
|
|
367
|
+
end
|
|
301
368
|
end
|
|
302
369
|
end
|
|
303
370
|
end
|
data/spec/lib/symbol_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'simplecov'
|
|
2
4
|
SimpleCov.command_name 'Rspec'
|
|
3
5
|
|
|
@@ -8,7 +10,7 @@ require 'pry'
|
|
|
8
10
|
require 'debug'
|
|
9
11
|
|
|
10
12
|
require 'active_support/testing/time_helpers'
|
|
11
|
-
|
|
13
|
+
require_relative '../lib/fat_core/all'
|
|
12
14
|
|
|
13
15
|
# This file was generated by the `rspec --init` command. Conventionally, all
|
|
14
16
|
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fat_core
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 7.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel E. Doherty
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: bin
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2025-11-25 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: activesupport
|
|
@@ -78,12 +79,14 @@ extensions: []
|
|
|
78
79
|
extra_rdoc_files: []
|
|
79
80
|
files:
|
|
80
81
|
- ".envrc"
|
|
82
|
+
- ".github/workflows/ruby.yml"
|
|
81
83
|
- ".gitignore"
|
|
82
84
|
- ".rspec"
|
|
83
85
|
- ".rubocop.yml"
|
|
84
86
|
- ".simplecov"
|
|
85
87
|
- ".travis.yml"
|
|
86
88
|
- ".yardopts"
|
|
89
|
+
- CHANGELOG.org
|
|
87
90
|
- Gemfile
|
|
88
91
|
- LICENSE.txt
|
|
89
92
|
- README.org
|
|
@@ -98,7 +101,6 @@ files:
|
|
|
98
101
|
- lib/fat_core/bigdecimal.rb
|
|
99
102
|
- lib/fat_core/enumerable.rb
|
|
100
103
|
- lib/fat_core/hash.rb
|
|
101
|
-
- lib/fat_core/kernel.rb
|
|
102
104
|
- lib/fat_core/nil.rb
|
|
103
105
|
- lib/fat_core/numeric.rb
|
|
104
106
|
- lib/fat_core/patches.rb
|
|
@@ -110,7 +112,6 @@ files:
|
|
|
110
112
|
- spec/lib/big_decimal_spec.rb
|
|
111
113
|
- spec/lib/enumerable_spec.rb
|
|
112
114
|
- spec/lib/hash_spec.rb
|
|
113
|
-
- spec/lib/kernel_spec.rb
|
|
114
115
|
- spec/lib/nil_class_spec.rb
|
|
115
116
|
- spec/lib/numeric_spec.rb
|
|
116
117
|
- spec/lib/range_spec.rb
|
|
@@ -122,6 +123,7 @@ licenses:
|
|
|
122
123
|
- MIT
|
|
123
124
|
metadata:
|
|
124
125
|
yard.run: yri
|
|
126
|
+
post_install_message:
|
|
125
127
|
rdoc_options: []
|
|
126
128
|
require_paths:
|
|
127
129
|
- lib
|
|
@@ -136,7 +138,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
136
138
|
- !ruby/object:Gem::Version
|
|
137
139
|
version: '0'
|
|
138
140
|
requirements: []
|
|
139
|
-
rubygems_version: 3.
|
|
141
|
+
rubygems_version: 3.5.23
|
|
142
|
+
signing_key:
|
|
140
143
|
specification_version: 4
|
|
141
144
|
summary: some useful core extensions
|
|
142
145
|
test_files: []
|
data/lib/fat_core/kernel.rb
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'fat_core/numeric'
|
|
4
|
-
|
|
5
|
-
module Kernel
|
|
6
|
-
# Run the given block and report the time it took to execute in
|
|
7
|
-
# hour-minute-second form.
|
|
8
|
-
#
|
|
9
|
-
# @example
|
|
10
|
-
# result = time_it 'Fibbonacci' do
|
|
11
|
-
# Fibbonacci.fib(30)
|
|
12
|
-
# end
|
|
13
|
-
# puts "For 30 its #{result}"
|
|
14
|
-
# => "Ran Fibonacci in 30:23"
|
|
15
|
-
#
|
|
16
|
-
# @param name [String, #to_s] an optional name to use for block in timing
|
|
17
|
-
# message.
|
|
18
|
-
# @return [Object] whatever the block returns
|
|
19
|
-
def time_it(name = 'block', &block)
|
|
20
|
-
start = Time.now
|
|
21
|
-
result = yield block
|
|
22
|
-
run_time = Time.now - start
|
|
23
|
-
puts "Ran #{name} in #{run_time.secs_to_hms}"
|
|
24
|
-
result
|
|
25
|
-
end
|
|
26
|
-
end
|