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.
@@ -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 =~ %r{^\s*/}
232
+ elsif matcher.match?(%r{^\s*/})
255
233
  re = matcher.as_regexp
256
- $& if to_s =~ re
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 all periods, commas, apostrophes, and asterisks (the punctuation
266
- # characters) from both self and `matcher`,
267
- # 2. Treat internal ':stuff' in the matcher as the equivalent of
268
- # '\bstuff.*?\b' in a regular expression, that is, match any word
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
- # 3. Treat leading ':' in the matcher as anchoring the match to the
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
- # 4. Treat ending ':' in the matcher as anchoring the match to the
260
+ # 7. Treat ending ':' in the matcher as anchoring the match to the
273
261
  # end of the target string,
274
- # 5. Require each component to match the beginning of a word boundary
275
- # 6. Ignore case in the match
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') #=> 'St Lukes Hospital'
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
- if matcher.start_with?(':')
292
- begin_anchor = true
293
- matcher.delete_prefix!(':')
294
- end
295
- if matcher.end_with?(':')
296
- end_anchor = true
297
- matcher.delete_suffix!(':')
298
- end
299
- target = gsub(/[\*.,']/, '')
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
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'fat_core/string'
3
+ require_relative 'string'
4
4
 
5
5
  module FatCore
6
6
  module Symbol
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FatCore
4
- MAJOR = 5
5
- MINOR = 6
4
+ MAJOR = 7
5
+ MINOR = 0
6
6
  PATCH = 1
7
7
 
8
8
  # FatCore version number
data/lib/fat_core.rb CHANGED
@@ -1,5 +1,5 @@
1
- require 'date'
2
- require 'active_support'
1
+ # frozen_string_literal: true
2
+
3
3
  require 'active_support/core_ext/object/blank'
4
4
  require 'active_support/core_ext/object/deep_dup'
5
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  require 'fat_core/array'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
  require 'fat_core/bigdecimal'
3
5
 
@@ -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
- it 'enumerates groups of size k' do
6
- letters = ('a'..'z').to_a
7
- letters.groups_of(3).each do |_k, grp|
8
- expect(grp.class).to eq Array
9
- if grp.last == 'z'
10
- expect(grp.size).to eq(2)
11
- expect(grp).to eq(['y', 'z'])
12
- else
13
- expect(grp.size).to eq(3)
14
- expect(grp.join).to match(/\A[a-z]{3}\z/)
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
- it 'enumerates each with first and last flags' do
20
- letters = ('a'..'z').to_a
21
- letters.each_with_flags do |l, first, last|
22
- if l == 'a'
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
- it 'returns nil enumerating a beginless Range' do
36
- bless = (..100)
37
- result = bless.each_with_flags { |_l, _first, _last| 44 }
38
- expect(result).to be_nil
39
- end
40
-
41
- it 'enumerates an endless Range' do
42
- eless = (1..)
43
- num = 0
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
@@ -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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
  require 'fat_core/nil'
3
5
 
@@ -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