fat_core 6.0.0 → 7.1.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 +61 -0
- data/Gemfile +5 -4
- data/README.org +1023 -58
- data/Rakefile +16 -3
- data/bin/console +1 -0
- data/fat_core.gemspec +6 -5
- 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 +78 -38
- data/lib/fat_core/symbol.rb +1 -1
- data/lib/fat_core/version.rb +3 -3
- 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 +96 -12
- data/spec/lib/symbol_spec.rb +2 -0
- data/spec/spec_helper.rb +3 -1
- metadata +13 -10
- 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,36 @@ 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. In the subject string replace periods and commas with a space (so
|
|
247
|
+
# they still act as word separators) but remove apostrophes, and
|
|
248
|
+
# asterisks so the user need not remember whether they were used when
|
|
249
|
+
# forming the matcher.
|
|
250
|
+
# 3. In the matcher, make any period, comma, asterisk, or apostrophe
|
|
251
|
+
# optional for the same reason.
|
|
252
|
+
# 4. Treat internal ':stuff' or ' :stuff' in the matcher as the equivalent
|
|
253
|
+
# of /\bstuff.*/ in a regular expression, that is, match any word
|
|
249
254
|
# starting with stuff in self,
|
|
250
|
-
#
|
|
255
|
+
# 5. Treat internal 'stuff: ' in the matcher as the equivalent
|
|
256
|
+
# of /.*stuff\b/ in a regular expression, that is, match any word
|
|
257
|
+
# ending with stuff in self,
|
|
258
|
+
# 6. A colon with no spaces around it is treated as belonging to the
|
|
259
|
+
# following word, requiring it to start with it, so 'some:stuff'
|
|
260
|
+
# requires 'some' anywhere followed by a word beginning with 'stuff',
|
|
261
|
+
# i.e., /some.*\bstuff/i,
|
|
262
|
+
# 7. Treat leading ':' in the matcher as anchoring the match to the
|
|
251
263
|
# beginning of the target string,
|
|
252
|
-
#
|
|
264
|
+
# 8. Treat ending ':' in the matcher as anchoring the match to the
|
|
253
265
|
# end of the target string,
|
|
254
|
-
#
|
|
255
|
-
#
|
|
266
|
+
# 9. Require each component to match some part of self, and
|
|
267
|
+
# 10. Ignore case in the match
|
|
256
268
|
#
|
|
257
269
|
# @example
|
|
258
270
|
# "St. Luke's Hospital".fuzzy_match('st lukes') #=> 'St Lukes'
|
|
259
271
|
# "St. Luke's Hospital".fuzzy_match('luk:hosp') #=> 'Lukes Hosp'
|
|
260
|
-
# "St. Luke's Hospital".fuzzy_match('st:spital') #=>
|
|
272
|
+
# "St. Luke's Hospital".fuzzy_match('st:spital') #=> nil
|
|
273
|
+
# "St. Luke's Hospital".fuzzy_match('st spital') #=> 'St Lukes Hospital'
|
|
261
274
|
# "St. Luke's Hospital".fuzzy_match('st:laks') #=> nil
|
|
262
275
|
# "St. Luke's Hospital".fuzzy_match(':lukes') #=> nil
|
|
263
276
|
# "St. Luke's Hospital".fuzzy_match('lukes:hospital:') #=> 'Lukes Hospital'
|
|
@@ -266,23 +279,20 @@ module FatCore
|
|
|
266
279
|
# @return [String] the unpunctuated part of self that matched
|
|
267
280
|
# @return [nil] if self did not match matcher
|
|
268
281
|
def fuzzy_match(matcher)
|
|
269
|
-
#
|
|
270
|
-
matcher = matcher.
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
regexp_string.sub!(/\.\*\?$/, '')
|
|
284
|
-
regexp_string.sub!(/\A/, '\\A') if begin_anchor
|
|
285
|
-
regexp_string.sub!(/\z/, '\\z') if end_anchor
|
|
282
|
+
# Make asterisks, periods, commas, and apostrophes optional
|
|
283
|
+
matcher = matcher.clean.gsub(/[\*.,']/, '\0?')
|
|
284
|
+
# Replace periods and commas with a space (so they are still word
|
|
285
|
+
# separators, e.g. 'WWW.WOLFRAM' -> 'WWW WOLFRAM' and 'AMZON,INC.' ->
|
|
286
|
+
# 'AMAZON INC') and remove asterisks and apostrophes
|
|
287
|
+
target = gsub(/[.,]/, ' ').gsub(/[\*']/, '').clean
|
|
288
|
+
regexp_string =
|
|
289
|
+
if matcher.match?(/[: ]/)
|
|
290
|
+
matcher.sub(/\A:/, "\\A").sub(/:\z/, "\\z")
|
|
291
|
+
.gsub(/:\s+/, "\\b.*").gsub(':', ".*\\b")
|
|
292
|
+
.gsub(/\s+/, ".*")
|
|
293
|
+
else
|
|
294
|
+
Regexp.escape(matcher)
|
|
295
|
+
end
|
|
286
296
|
regexp = /#{regexp_string}/i
|
|
287
297
|
matched_text =
|
|
288
298
|
if (match = regexp.match(target))
|
|
@@ -317,7 +327,6 @@ module FatCore
|
|
|
317
327
|
flags |= Regexp::MULTILINE if opts.include?('m')
|
|
318
328
|
end
|
|
319
329
|
flags = nil if flags.zero?
|
|
320
|
-
# body = Regexp.quote(body) if REGEXP_META_CHARACTERS.include?(body)
|
|
321
330
|
Regexp.new(body, flags)
|
|
322
331
|
else
|
|
323
332
|
Regexp.new(Regexp.quote(self), Regexp::IGNORECASE)
|
|
@@ -388,3 +397,34 @@ class String
|
|
|
388
397
|
# @!parse include FatCore::String
|
|
389
398
|
# @!parse extend FatCore::String::ClassMethods
|
|
390
399
|
end
|
|
400
|
+
|
|
401
|
+
module StringPred
|
|
402
|
+
refine String do
|
|
403
|
+
# This is a kludgy version of #pred (Ruby does define it for a good
|
|
404
|
+
# reason, namely there is no unique string for which x.pred.succ == x).
|
|
405
|
+
# Still, for my Range extensions, it helps to have this limited version to
|
|
406
|
+
# produce a usable #pred for the #gaps method.
|
|
407
|
+
def pred
|
|
408
|
+
str = clean
|
|
409
|
+
return "9" if str.length == 1 && str[0] == 'A'
|
|
410
|
+
return "Z" if str.length == 1 && str[0] == 'a'
|
|
411
|
+
return "a" if str.length == 1 && str[0] == '0'
|
|
412
|
+
return "" if str.empty?
|
|
413
|
+
|
|
414
|
+
unless str.match?(/\A[A-Za-z0-9]+\z/)
|
|
415
|
+
raise NoMethodError, "undefined method :pred for \"#{self}\":String"
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
case str[-1]
|
|
419
|
+
when 'A'
|
|
420
|
+
str[0..-2].pred + 'Z'
|
|
421
|
+
when 'a'
|
|
422
|
+
str[0..-2].pred + 'z'
|
|
423
|
+
when '0'
|
|
424
|
+
str[0..-2].pred + '9'
|
|
425
|
+
else
|
|
426
|
+
str[0..-2] + (str[-1].ord - 1).chr
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
end
|
|
430
|
+
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,37 +257,61 @@ 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 '
|
|
251
|
-
expect('
|
|
252
|
-
expect('
|
|
264
|
+
it 'replaces periods and commas with a space so they are still word separators' do
|
|
265
|
+
expect('WWW.WOLFRAM.COM'.fuzzy_match('wolf')).to be_truthy
|
|
266
|
+
expect('AMAZON,INC'.fuzzy_match('amazon inc')).to be_truthy
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
it 'modifies self by removing asterisks and apostrophes' do
|
|
270
|
+
expect('WWW*WOLFRAM*COM'.fuzzy_match('wolf')).to be_truthy
|
|
271
|
+
expect('E*TRADE'.fuzzy_match('etrade')).to be_truthy
|
|
272
|
+
expect('WWW*WOLFRAM*COM'.fuzzy_match(':wolf')).to be_falsy
|
|
273
|
+
expect('WWW.WOLFRAM.COM'.fuzzy_match('wolf')).to be_truthy
|
|
274
|
+
expect('AMAZON,INC'.fuzzy_match('amazon inc')).to be_truthy
|
|
253
275
|
end
|
|
254
276
|
|
|
255
|
-
it '
|
|
277
|
+
it 'treats internal space as dot-star' do
|
|
256
278
|
expect('Hello world'.fuzzy_match('hel wor')).to be_truthy
|
|
279
|
+
expect('Hello, world'.fuzzy_match('el or')).to be_truthy
|
|
257
280
|
expect('Hello, world'.fuzzy_match('hel ox')).to be_falsy
|
|
281
|
+
expect('Hello, what is with the world?'.fuzzy_match('at wi or')).to be_truthy
|
|
258
282
|
end
|
|
259
283
|
|
|
260
284
|
it 'fuzzy matches colon-separated parts' do
|
|
261
285
|
expect('Hello:world'.fuzzy_match('hel:wor')).to be_truthy
|
|
262
|
-
expect('Hello:world'.fuzzy_match('hel:
|
|
286
|
+
expect('Hello:world'.fuzzy_match('hel :wor')).to be_truthy
|
|
287
|
+
expect('Hello:world'.fuzzy_match('hel: wor')).to be_falsy
|
|
288
|
+
expect('Hello:world'.fuzzy_match('hel:orld')).to be_falsy
|
|
289
|
+
expect("Hello, 'world'".fuzzy_match('hel:wor')).to be_truthy
|
|
290
|
+
expect('Hello "world"'.fuzzy_match('hel:world')).to be_truthy
|
|
263
291
|
end
|
|
264
292
|
|
|
265
|
-
it 'treats an internal `:stuff
|
|
293
|
+
it 'treats an internal `:stuff` as \bstuff.*' do
|
|
266
294
|
expect('Hello, what is with the world?'.fuzzy_match('wha:wi:wor')).to be_truthy
|
|
295
|
+
expect('Hello, what is with the world?'.fuzzy_match('hat :wi :wor')).to be_truthy
|
|
267
296
|
expect('Hello:world'.fuzzy_match('what:or')).to be_falsy
|
|
268
297
|
expect('Hello, what=+&is (with) the world?'.fuzzy_match('wha:wi:wor')).to be_truthy
|
|
269
298
|
end
|
|
270
299
|
|
|
300
|
+
it 'treats an internal `stuff: ` as stuff\b.*' do
|
|
301
|
+
expect('Hello, what is with the world?'.fuzzy_match('llo: th: :wor')).to be_truthy
|
|
302
|
+
expect('Hello:world'.fuzzy_match('llox: ')).to be_falsy
|
|
303
|
+
expect('Hello, what=+&is (with) the world?'.fuzzy_match('at: ith: the')).to be_truthy
|
|
304
|
+
end
|
|
305
|
+
|
|
271
306
|
it 'requires end-anchor for ending colon' do
|
|
272
307
|
expect('Hello, to the world'.fuzzy_match('hel:world:')).to eq('Hello to the world')
|
|
308
|
+
expect('Hello, to the world '.fuzzy_match('hel:world:')).to eq('Hello to the world')
|
|
273
309
|
expect('Hello, to the world today'.fuzzy_match('to:world:')).to be_nil
|
|
274
310
|
end
|
|
275
311
|
|
|
276
312
|
it 'requires start-anchor for leading colon' do
|
|
277
313
|
expect('Hello, to the world'.fuzzy_match(':hel:the')).to eq('Hello to the')
|
|
314
|
+
expect(' Hello, to the world'.fuzzy_match(':hel:the')).to eq('Hello to the')
|
|
278
315
|
expect('Hello, to the world today'.fuzzy_match(':world:today')).to be_nil
|
|
279
316
|
end
|
|
280
317
|
|
|
@@ -289,15 +326,62 @@ the people, for the people, shall not perish from the earth."
|
|
|
289
326
|
expect('Hello:world'.matches_with('/^h.*r/')).to eq('Hello:wor')
|
|
290
327
|
end
|
|
291
328
|
|
|
292
|
-
it '
|
|
329
|
+
it 'make periods, commas, and apostrophes optional when matching' do
|
|
293
330
|
expect("St. Luke's".fuzzy_match('st lukes')).to eq('St Lukes')
|
|
294
|
-
expect(
|
|
331
|
+
expect("St. Luke's".fuzzy_match('st. luke\'s')).to eq('St Lukes')
|
|
332
|
+
expect("St Lukes".fuzzy_match('st. luke\'s')).to eq('St Lukes')
|
|
295
333
|
expect('St Lukes, Inc.'.fuzzy_match('st luke inc')).to eq('St Lukes Inc')
|
|
334
|
+
expect('St Lukes, Inc.'.fuzzy_match('st lukes, inc')).to eq('St Lukes Inc')
|
|
296
335
|
expect('E*TRADE'.fuzzy_match('etrade')).to eq('ETRADE')
|
|
297
336
|
# Does not recognize non-alphanumerics as start of string.
|
|
298
337
|
expect('The 1 Dollar Store'.fuzzy_match('1 stor')).to be_truthy
|
|
299
338
|
expect('The $1 Dollar Store'.fuzzy_match('$1 stor')).to be_falsy
|
|
300
339
|
end
|
|
340
|
+
|
|
341
|
+
it 'performs examples in documentation' do
|
|
342
|
+
expect("St. Luke's".fuzzy_match('st lukes')).to eq('St Lukes')
|
|
343
|
+
expect("St. Luke's Hospital".fuzzy_match('st lukes')).to eq('St Lukes')
|
|
344
|
+
expect("St. Luke's Hospital".fuzzy_match('luk:hosp')).to eq('Lukes Hosp')
|
|
345
|
+
expect("St. Luke's Hospital".fuzzy_match('st:spital')).to be_nil
|
|
346
|
+
expect("St. Luke's Hospital".fuzzy_match('st spital')).to eq('St Lukes Hospital')
|
|
347
|
+
expect("St. Luke's Hospital".fuzzy_match('st:laks')).to be_nil
|
|
348
|
+
expect("St. Luke's Hospital".fuzzy_match(':lukes')).to be_nil
|
|
349
|
+
expect("St. Luke's Hospital".fuzzy_match('lukes:hospital')).to eq('Lukes Hospital')
|
|
350
|
+
end
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
describe '#matches_with' do
|
|
354
|
+
it 'matches with another string containing a plain string' do
|
|
355
|
+
expect('Hello, world'.matches_with('or')).to be_truthy
|
|
356
|
+
expect('Hello, world'.matches_with('ox')).to be_falsy
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
it 'matches with another string containing re' do
|
|
360
|
+
expect('Hello, world'.matches_with('/or/')).to be_truthy
|
|
361
|
+
expect('Hello, world'.matches_with('/ox/')).to be_falsy
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
it 'performs examples in documentation with just strings' do
|
|
365
|
+
expect("St. Luke's".matches_with('st lukes')).to eq('St Lukes')
|
|
366
|
+
expect("St. Luke's Hospital".matches_with('st lukes')).to eq('St Lukes')
|
|
367
|
+
expect("St. Luke's Hospital".matches_with('luk:hosp')).to eq('Lukes Hosp')
|
|
368
|
+
expect("St. Luke's Hospital".matches_with('st:spital')).to be_nil
|
|
369
|
+
expect("St. Luke's Hospital".matches_with('st spital')).to eq('St Lukes Hospital')
|
|
370
|
+
expect("St. Luke's Hospital".matches_with('st:laks')).to be_nil
|
|
371
|
+
expect("St. Luke's Hospital".matches_with(':lukes')).to be_nil
|
|
372
|
+
expect("St. Luke's Hospital".matches_with('lukes:hospital')).to eq('Lukes Hospital')
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
it 'performs examples in documentation with regexes' do
|
|
376
|
+
expect("St. Luke's".matches_with('/st\s*lukes/')).to eq('St Lukes')
|
|
377
|
+
expect("St. Luke's Hospital".matches_with('/st lukes/')).to eq('St Lukes')
|
|
378
|
+
expect("St. Luke's Hospital".matches_with('/luk.*\bhosp/')).to eq('Lukes Hosp')
|
|
379
|
+
expect("St. Luke's Hospital".matches_with('/st(.*)spital\z/')).to eq('St Lukes Hospital')
|
|
380
|
+
expect("St. Luke's Hospital".matches_with('/st spital/')).to be_nil
|
|
381
|
+
expect("St. Luke's Hospital".matches_with('/st.*laks/')).to be_nil
|
|
382
|
+
expect("St. Luke's Hospital".matches_with('/\Alukes/')).to be_nil
|
|
383
|
+
expect("St. Luke's Hospital".matches_with('/lukes hospital/')).to eq('Lukes Hospital')
|
|
384
|
+
end
|
|
301
385
|
end
|
|
302
386
|
end
|
|
303
387
|
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`.
|