fat_core 4.10.0 → 4.12.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|