fat_core 4.10.0 → 4.12.0
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/lib/fat_core/date.rb +38 -4
- data/lib/fat_core/string.rb +21 -5
- data/lib/fat_core/version.rb +1 -1
- data/spec/lib/date_spec.rb +71 -0
- data/spec/lib/string_spec.rb +18 -0
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 293a92293691aebd9771c017fa1dfeb9f9935bbb3832a19ec3494df49a75a176
|
4
|
+
data.tar.gz: 273ca4995d0e8b5d95cb5103ce520643f5aca983a0d855b083deb7d052033b63
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b6f8fe6dc824a53d5087a2565a16bda84f7c311514346b3c0dcc58d9822b3dc84b3a93f9070dc1d27fce4aba90841556a3251a3e72d065f92b78f82402e9f73a
|
7
|
+
data.tar.gz: 2aab09471276331aa009b76250e9dd163ca1512b135170495bd5d899cd46d575d3aa0c29d14a923781ee99606ebffb4a7d434a37c47d10be73c8dba363f254d0
|
data/lib/fat_core/date.rb
CHANGED
@@ -119,6 +119,17 @@ module FatCore
|
|
119
119
|
|
120
120
|
# :category: Queries
|
121
121
|
|
122
|
+
# Number of days in self's month
|
123
|
+
# @return [Integer]
|
124
|
+
def days_in_month
|
125
|
+
self.class.days_in_month(year, month)
|
126
|
+
end
|
127
|
+
|
128
|
+
# :category: Queries
|
129
|
+
# @group Queries
|
130
|
+
|
131
|
+
# :category: Queries
|
132
|
+
|
122
133
|
# Self's calendar "half" by analogy to calendar quarters: 1 or 2, depending
|
123
134
|
# on whether the date falls in the first or second half of the calendar
|
124
135
|
# year.
|
@@ -357,10 +368,30 @@ module FatCore
|
|
357
368
|
# @param from_date [::Date] the middle of the six-month range
|
358
369
|
# @return [Boolean]
|
359
370
|
def within_6mos_of?(from_date)
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
371
|
+
from_date = Date.parse(from_date) unless from_date.is_a?(Date)
|
372
|
+
from_day = from_date.day
|
373
|
+
if [28, 29, 30, 31].include?(from_day)
|
374
|
+
# Near the end of the month, we need to make sure that when we go
|
375
|
+
# forward or backwards 6 months, we do not go past the end of the
|
376
|
+
# destination month when finding the "corresponding" day in that
|
377
|
+
# month, per Stella v. Graham Page Motors. This refinement was
|
378
|
+
# endorsed in the Jammies International case. After we find the
|
379
|
+
# corresponding day in the target month, then add two days (for the
|
380
|
+
# month six months before the from_date) or subtract two days (for the
|
381
|
+
# month six months after the from_date) to get the first and last days
|
382
|
+
# of the "within a period of less than six months" date range.
|
383
|
+
start_month = from_date.beginning_of_month - 6.months
|
384
|
+
start_days = start_month.days_in_month
|
385
|
+
start_date = ::Date.new(start_month.year, start_month.month, [start_days, from_day].min) + 2.days
|
386
|
+
end_month = from_date.beginning_of_month + 6.months
|
387
|
+
end_days = end_month.days_in_month
|
388
|
+
end_date = ::Date.new(end_month.year, end_month.month, [end_days, from_day].min) - 2.days
|
389
|
+
else
|
390
|
+
# ::Date 6 calendar months before self
|
391
|
+
start_date = from_date - 6.months + 2.days
|
392
|
+
end_date = from_date + 6.months - 2.days
|
393
|
+
end
|
394
|
+
(start_date..end_date).cover?(self)
|
364
395
|
end
|
365
396
|
|
366
397
|
# Return whether this date is Easter Sunday for the year in which it falls
|
@@ -1002,6 +1033,9 @@ module FatCore
|
|
1002
1033
|
if mon == 1 && mday == 1
|
1003
1034
|
# New Years (January 1),
|
1004
1035
|
true
|
1036
|
+
elsif mon == 6 && mday == 19 && year >= 2021
|
1037
|
+
# Juneteenth,
|
1038
|
+
true
|
1005
1039
|
elsif mon == 7 && mday == 4
|
1006
1040
|
# Independence Day (July 4),
|
1007
1041
|
true
|
data/lib/fat_core/string.rb
CHANGED
@@ -245,28 +245,44 @@ module FatCore
|
|
245
245
|
#
|
246
246
|
# 1. Remove all periods, commas, apostrophes, and asterisks (the punctuation
|
247
247
|
# characters) from both self and `matcher`,
|
248
|
-
# 2. Treat ':' in the matcher as the equivalent of '.*' in a
|
249
|
-
# expression, that is, match anything in self,
|
250
|
-
# 3.
|
251
|
-
#
|
248
|
+
# 2. Treat internal ':' in the matcher as the equivalent of '.*' in a
|
249
|
+
# regular expression, that is, match anything in self,
|
250
|
+
# 3. Treat leading ':' in the matcher as anchoring the match to the
|
251
|
+
# beginning of the target string,
|
252
|
+
# 4. Treat ending ':' in the matcher as anchoring the match to the
|
253
|
+
# end of the target string,
|
254
|
+
# 5. Require each component to match the beginning of a word boundary
|
255
|
+
# 6. Ignore case in the match
|
252
256
|
#
|
253
257
|
# @example
|
254
258
|
# "St. Luke's Hospital".fuzzy_match('st lukes') #=> 'St Lukes'
|
255
259
|
# "St. Luke's Hospital".fuzzy_match('luk:hosp') #=> 'Lukes Hosp'
|
256
260
|
# "St. Luke's Hospital".fuzzy_match('st:spital') #=> 'St Lukes Hospital'
|
257
261
|
# "St. Luke's Hospital".fuzzy_match('st:laks') #=> nil
|
262
|
+
# "St. Luke's Hospital".fuzzy_match(':lukes') #=> nil
|
263
|
+
# "St. Luke's Hospital".fuzzy_match('lukes:hospital:') #=> 'Lukes Hospital'
|
258
264
|
#
|
259
265
|
# @param matcher [String] pattern to test against where ':' is wildcard
|
260
266
|
# @return [String] the unpunctuated part of self that matched
|
261
267
|
# @return [nil] if self did not match matcher
|
262
268
|
def fuzzy_match(matcher)
|
263
269
|
# Remove periods, asterisks, commas, and apostrophes
|
264
|
-
matcher = matcher.gsub(/[\*.,']/, '')
|
270
|
+
matcher = matcher.strip.gsub(/[\*.,']/, '')
|
271
|
+
if matcher.start_with?(':')
|
272
|
+
begin_anchor = true
|
273
|
+
matcher.sub!(/\A:/, '')
|
274
|
+
end
|
275
|
+
if matcher.end_with?(':')
|
276
|
+
end_anchor = true
|
277
|
+
matcher.sub!(/:\z/, '')
|
278
|
+
end
|
265
279
|
target = gsub(/[\*.,']/, '')
|
266
280
|
matchers = matcher.split(/[: ]+/)
|
267
281
|
regexp_string = matchers.map { |m| ".*?\\b#{Regexp.escape(m)}.*?" }.join('[: ]')
|
268
282
|
regexp_string.sub!(/^\.\*\?/, '')
|
269
283
|
regexp_string.sub!(/\.\*\?$/, '')
|
284
|
+
regexp_string.sub!(/\A/, '\\A') if begin_anchor
|
285
|
+
regexp_string.sub!(/\z/, '\\z') if end_anchor
|
270
286
|
regexp = /#{regexp_string}/i
|
271
287
|
matched_text =
|
272
288
|
if (match = regexp.match(target))
|
data/lib/fat_core/version.rb
CHANGED
data/spec/lib/date_spec.rb
CHANGED
@@ -837,6 +837,65 @@ describe Date do
|
|
837
837
|
expect(Date.parse('2014-01-12'))
|
838
838
|
.to be_within_6mos_of(Date.parse('2014-07-10'))
|
839
839
|
end
|
840
|
+
|
841
|
+
it "knows if it's within 6 months of another date if it's near end of month" do
|
842
|
+
# This tests for the Jammies Interntional twist where there is no
|
843
|
+
# corresponding day in the sixth month before or after the given date.
|
844
|
+
|
845
|
+
# Looking backward to Feb
|
846
|
+
expect(Date.parse('2014-02-28'))
|
847
|
+
.not_to be_within_6mos_of(Date.parse('2014-08-31'))
|
848
|
+
expect(Date.parse('2014-03-01'))
|
849
|
+
.not_to be_within_6mos_of(Date.parse('2014-08-31'))
|
850
|
+
expect(Date.parse('2014-03-02'))
|
851
|
+
.to be_within_6mos_of(Date.parse('2014-08-31'))
|
852
|
+
# Looking forward to Feb
|
853
|
+
expect(Date.parse('2015-02-28'))
|
854
|
+
.not_to be_within_6mos_of(Date.parse('2014-08-31'))
|
855
|
+
expect(Date.parse('2015-02-27'))
|
856
|
+
.not_to be_within_6mos_of(Date.parse('2014-08-31'))
|
857
|
+
expect(Date.parse('2015-02-26'))
|
858
|
+
.to be_within_6mos_of(Date.parse('2014-08-31'))
|
859
|
+
# Same in a leap year, backward
|
860
|
+
expect(Date.parse('2012-02-29'))
|
861
|
+
.not_to be_within_6mos_of(Date.parse('2012-08-31'))
|
862
|
+
expect(Date.parse('2012-03-01'))
|
863
|
+
.not_to be_within_6mos_of(Date.parse('2012-08-31'))
|
864
|
+
expect(Date.parse('2012-03-02'))
|
865
|
+
.to be_within_6mos_of(Date.parse('2012-08-31'))
|
866
|
+
# Same in a leap year, forward
|
867
|
+
expect(Date.parse('2012-02-29'))
|
868
|
+
.not_to be_within_6mos_of(Date.parse('2011-08-31'))
|
869
|
+
expect(Date.parse('2012-02-28'))
|
870
|
+
.not_to be_within_6mos_of(Date.parse('2011-08-31'))
|
871
|
+
expect(Date.parse('2012-02-27'))
|
872
|
+
.to be_within_6mos_of(Date.parse('2011-08-31'))
|
873
|
+
|
874
|
+
# Now try from October to April, as 31->30 test.
|
875
|
+
expect(Date.parse('2012-04-30'))
|
876
|
+
.not_to be_within_6mos_of(Date.parse('2012-10-31'))
|
877
|
+
expect(Date.parse('2012-05-01'))
|
878
|
+
.not_to be_within_6mos_of(Date.parse('2012-10-31'))
|
879
|
+
expect(Date.parse('2012-05-02'))
|
880
|
+
.to be_within_6mos_of(Date.parse('2012-10-31'))
|
881
|
+
# And forward
|
882
|
+
expect(Date.parse('2013-04-30'))
|
883
|
+
.not_to be_within_6mos_of(Date.parse('2012-10-31'))
|
884
|
+
expect(Date.parse('2013-04-29'))
|
885
|
+
.not_to be_within_6mos_of(Date.parse('2012-10-31'))
|
886
|
+
expect(Date.parse('2013-04-28'))
|
887
|
+
.to be_within_6mos_of(Date.parse('2012-10-31'))
|
888
|
+
|
889
|
+
# It's not symmetrical: notice the second example here is within six
|
890
|
+
# months if measured from April, but not if measured from October.
|
891
|
+
expect(Date.parse('2012-10-31'))
|
892
|
+
.not_to be_within_6mos_of(Date.parse('2013-04-30'))
|
893
|
+
expect(Date.parse('2012-10-31'))
|
894
|
+
.to be_within_6mos_of(Date.parse('2013-04-29'))
|
895
|
+
expect(Date.parse('2012-10-31'))
|
896
|
+
.to be_within_6mos_of(Date.parse('2013-04-28'))
|
897
|
+
|
898
|
+
end
|
840
899
|
end
|
841
900
|
|
842
901
|
describe 'holidays' do
|
@@ -948,6 +1007,18 @@ describe Date do
|
|
948
1007
|
expect(Date.parse('2014-11-23')).to be_fed_holiday
|
949
1008
|
end
|
950
1009
|
|
1010
|
+
it 'knows that Juneteenth is a federal holiday from 2021' do
|
1011
|
+
expect(Date.parse('2020-06-19')).not_to be_fed_holiday
|
1012
|
+
# Saturday
|
1013
|
+
expect(Date.parse('2021-06-19')).to be_fed_holiday
|
1014
|
+
# Observed Friday
|
1015
|
+
expect(Date.parse('2021-06-18')).to be_fed_holiday
|
1016
|
+
# Sunday
|
1017
|
+
expect(Date.parse('2022-06-19')).to be_fed_holiday
|
1018
|
+
# Observed Monday
|
1019
|
+
expect(Date.parse('2022-06-20')).to be_fed_holiday
|
1020
|
+
end
|
1021
|
+
|
951
1022
|
it 'should know if its an NYSE holiday' do
|
952
1023
|
################# 2014 2015 2016
|
953
1024
|
# New Year's Day January 1 January 1 January 1
|
data/spec/lib/string_spec.rb
CHANGED
@@ -269,6 +269,21 @@ the people, for the people, shall not perish from the earth."
|
|
269
269
|
expect('Hello:world'.fuzzy_match('hel:ox')).to be_falsy
|
270
270
|
end
|
271
271
|
|
272
|
+
it 'requires end-anchor for ending colon' do
|
273
|
+
expect('Hello, to the world'.fuzzy_match('hel:world:')).to eq('Hello to the world')
|
274
|
+
expect('Hello, to the world today'.fuzzy_match('to:world:')).to be_nil
|
275
|
+
end
|
276
|
+
|
277
|
+
it 'requires start-anchor for leading colon' do
|
278
|
+
expect('Hello, to the world'.fuzzy_match(':hel:the')).to eq('Hello to the')
|
279
|
+
expect('Hello, to the world today'.fuzzy_match(':world:today')).to be_nil
|
280
|
+
end
|
281
|
+
|
282
|
+
it 'requires start-anchor and end-anchor for leading and ending colon' do
|
283
|
+
expect('Hello, to the world'.fuzzy_match(':hel:world:')).to eq('Hello to the world')
|
284
|
+
expect('Hello, to the world today'.fuzzy_match('hel:world:')).to be_falsy
|
285
|
+
end
|
286
|
+
|
272
287
|
it 'should return the matched text' do
|
273
288
|
expect('Hello:world'.fuzzy_match('hel')).to eq('Hel')
|
274
289
|
expect('Hello:world'.fuzzy_match('hel:wor')).to eq('Hello:wor')
|
@@ -280,6 +295,9 @@ the people, for the people, shall not perish from the earth."
|
|
280
295
|
expect('St Lukes'.fuzzy_match('st. luke\'s')).to eq('St Lukes')
|
281
296
|
expect('St Lukes, Inc.'.fuzzy_match('st luke inc')).to eq('St Lukes Inc')
|
282
297
|
expect('E*TRADE'.fuzzy_match('etrade')).to eq('ETRADE')
|
298
|
+
# Does not recognize non-alphanumerics as start of string.
|
299
|
+
expect('The 1 Dollar Store'.fuzzy_match('1 stor')).to be_truthy
|
300
|
+
expect('The $1 Dollar Store'.fuzzy_match('$1 stor')).to be_falsy
|
283
301
|
end
|
284
302
|
end
|
285
303
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fat_core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel E. Doherty
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-09-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: simplecov
|
@@ -219,7 +219,7 @@ licenses:
|
|
219
219
|
- MIT
|
220
220
|
metadata:
|
221
221
|
yard.run: yri
|
222
|
-
post_install_message:
|
222
|
+
post_install_message:
|
223
223
|
rdoc_options: []
|
224
224
|
require_paths:
|
225
225
|
- lib
|
@@ -234,8 +234,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
234
234
|
- !ruby/object:Gem::Version
|
235
235
|
version: '0'
|
236
236
|
requirements: []
|
237
|
-
rubygems_version: 3.3.
|
238
|
-
signing_key:
|
237
|
+
rubygems_version: 3.3.7
|
238
|
+
signing_key:
|
239
239
|
specification_version: 4
|
240
240
|
summary: fat_core provides some useful core extensions
|
241
241
|
test_files:
|