casual_support 1.0.0 → 2.0.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/LICENSE.txt +1 -1
- data/README.md +52 -17
- data/Rakefile +13 -0
- data/benchmarks/comparable/at_least.rb +9 -0
- data/benchmarks/comparable/at_most.rb +9 -0
- data/benchmarks/hash/putbang.rb +13 -0
- data/benchmarks/integer/to_hex.rb +34 -0
- data/benchmarks/string/after.rb +22 -0
- data/benchmarks/string/after_last.rb +22 -0
- data/benchmarks/string/before.rb +23 -0
- data/benchmarks/string/before_last.rb +22 -0
- data/benchmarks/string/between.rb +21 -0
- data/benchmarks/string/drop.rb +18 -0
- data/benchmarks/string/first.rb +23 -0
- data/benchmarks/string/from.rb +15 -0
- data/benchmarks/string/last.rb +15 -0
- data/benchmarks/string/prefix.rb +12 -0
- data/benchmarks/string/suffix.rb +12 -0
- data/benchmarks/string/to.rb +15 -0
- data/benchmarks/time/to_hms.rb +12 -0
- data/benchmarks/time/to_ymd.rb +12 -0
- data/casual_support.gemspec +4 -3
- data/lib/casual_support.rb +8 -8
- data/lib/casual_support/comparable.rb +3 -0
- data/lib/casual_support/comparable/at_least.rb +11 -0
- data/lib/casual_support/comparable/at_most.rb +13 -0
- data/lib/casual_support/comparable/clamp.rb +16 -0
- data/lib/casual_support/date.rb +1 -1
- data/lib/casual_support/date/to_ymd.rb +1 -1
- data/lib/casual_support/enumerable.rb +2 -2
- data/lib/casual_support/enumerable/index_to.rb +2 -2
- data/lib/casual_support/hash.rb +1 -1
- data/lib/casual_support/hash/putbang.rb +15 -0
- data/lib/casual_support/integer.rb +1 -1
- data/lib/casual_support/integer/to_hex.rb +2 -8
- data/lib/casual_support/string.rb +13 -4
- data/lib/casual_support/string/after.rb +15 -0
- data/lib/casual_support/string/after_last.rb +14 -0
- data/lib/casual_support/string/before.rb +14 -0
- data/lib/casual_support/string/before_last.rb +15 -0
- data/lib/casual_support/string/between.rb +16 -0
- data/lib/casual_support/string/drop.rb +2 -1
- data/lib/casual_support/string/first.rb +17 -0
- data/lib/casual_support/string/from.rb +8 -0
- data/lib/casual_support/string/last.rb +18 -0
- data/lib/casual_support/string/lchomp.rb +16 -0
- data/lib/casual_support/string/prefix.rb +13 -0
- data/lib/casual_support/string/suffix.rb +13 -0
- data/lib/casual_support/string/to.rb +9 -0
- data/lib/casual_support/time.rb +2 -1
- data/lib/casual_support/time/to_hms.rb +14 -0
- data/lib/casual_support/time/to_ymd.rb +14 -0
- data/lib/casual_support/version.rb +1 -1
- metadata +71 -18
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/lib/casual_support/hash/setbang.rb +0 -16
- data/lib/casual_support/numeric.rb +0 -2
- data/lib/casual_support/numeric/at_least_most.rb +0 -21
- data/lib/casual_support/numeric/constrain.rb +0 -16
- data/lib/casual_support/string/before_after.rb +0 -59
- data/lib/casual_support/string/first_last.rb +0 -15
- data/lib/casual_support/string/from_to.rb +0 -15
- data/lib/casual_support/time/ymd_hms.rb +0 -27
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'benchmark/inputs'
|
2
|
+
require_relative '../../lib/casual_support'
|
3
|
+
|
4
|
+
|
5
|
+
FORMAT = '%Y-%m-%d'
|
6
|
+
|
7
|
+
Benchmark.inputs([Time.new(1999, 12, 31, 23, 59, 59)]) do |job|
|
8
|
+
job.report('Time#to_ymd'){|t| t.to_ymd }
|
9
|
+
job.report('Time#strftime'){|t| t.strftime('%Y-%m-%d') }
|
10
|
+
job.report('Time#strftime(CONST)'){|t| t.strftime(FORMAT) }
|
11
|
+
job.compare!
|
12
|
+
end
|
data/casual_support.gemspec
CHANGED
@@ -9,8 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Jonathan Hefner"]
|
10
10
|
spec.email = ["jonathan.hefner@gmail.com"]
|
11
11
|
|
12
|
-
spec.summary = %q{Utility
|
13
|
-
spec.description = %q{Utility methods as extensions to Ruby core objects. Stuff I want in Active Support.}
|
12
|
+
spec.summary = %q{Utility extensions to core objects, a la Active Support}
|
14
13
|
spec.homepage = "https://github.com/jonathanhefner/casual_support"
|
15
14
|
spec.license = "MIT"
|
16
15
|
|
@@ -22,6 +21,8 @@ Gem::Specification.new do |spec|
|
|
22
21
|
spec.add_runtime_dependency 'activesupport', '>= 3.1', '< 5.1'
|
23
22
|
|
24
23
|
spec.add_development_dependency "bundler", "~> 1.12"
|
25
|
-
spec.add_development_dependency "rake", "~>
|
24
|
+
spec.add_development_dependency "rake", "~> 11.1"
|
26
25
|
spec.add_development_dependency "minitest", "~> 5.0"
|
26
|
+
spec.add_development_dependency "yard", "~> 0.9"
|
27
|
+
spec.add_development_dependency "benchmark-inputs", "~> 1.0"
|
27
28
|
end
|
data/lib/casual_support.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
require_relative 'casual_support/version'
|
2
|
+
require_relative 'casual_support/comparable'
|
3
|
+
require_relative 'casual_support/date'
|
4
|
+
require_relative 'casual_support/enumerable'
|
5
|
+
require_relative 'casual_support/hash'
|
6
|
+
require_relative 'casual_support/integer'
|
7
|
+
require_relative 'casual_support/string'
|
8
|
+
require_relative 'casual_support/time'
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Comparable
|
2
|
+
|
3
|
+
# Enforces an upper bound for the value.
|
4
|
+
#
|
5
|
+
# @param [Comparable] limit upper bound
|
6
|
+
# @return [Comparable] value constrained by the upper bound
|
7
|
+
def at_most(limit)
|
8
|
+
self > limit ? limit : self
|
9
|
+
end
|
10
|
+
|
11
|
+
alias_method :cap, :at_most
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Comparable
|
2
|
+
|
3
|
+
# Clamps the value to a closed interval.
|
4
|
+
#
|
5
|
+
# Also see https://bugs.ruby-lang.org/issues/10594
|
6
|
+
#
|
7
|
+
# @param [Comparable] low lower bound
|
8
|
+
# @param [Comparable] high upper bound
|
9
|
+
# @return [Comparable] value constrained to the bounds
|
10
|
+
def clamp(low, high)
|
11
|
+
return low if self < low
|
12
|
+
return high if self > high
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
data/lib/casual_support/date.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
require_relative 'date/to_ymd'
|
@@ -1,2 +1,2 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require_relative 'enumerable/duplicates'
|
2
|
+
require_relative 'enumerable/index_to'
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require_relative '../hash/putbang'
|
2
2
|
|
3
3
|
module Enumerable
|
4
4
|
|
@@ -10,7 +10,7 @@ module Enumerable
|
|
10
10
|
# @yieldreturn value to associate with the +elem+ key
|
11
11
|
# @return [Hash] hash with the +Enumerable+'s elements as keys
|
12
12
|
def index_to()
|
13
|
-
self.reduce({}){|h, k| h.
|
13
|
+
self.reduce({}){|h, k| h.put!(k, (yield k)) }
|
14
14
|
end
|
15
15
|
|
16
16
|
end
|
data/lib/casual_support/hash.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
require_relative 'hash/putbang'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Hash
|
2
|
+
|
3
|
+
# Associates a key-value a la +Hash#[]=+, but returns the modified
|
4
|
+
# Hash instead of the value. Useful with +#reduce+, and faster than
|
5
|
+
# +Hash#merge!+.
|
6
|
+
#
|
7
|
+
# @param key
|
8
|
+
# @param value
|
9
|
+
# @return [Hash] the modified hash
|
10
|
+
def put!(key, value)
|
11
|
+
self[key] = value
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
require_relative 'integer/to_hex'
|
@@ -5,16 +5,10 @@ class Integer
|
|
5
5
|
# width, the string will be returned unaltered (without padding or
|
6
6
|
# truncation).
|
7
7
|
#
|
8
|
-
# Without the need for zero-padding, this method is ~7% slower than
|
9
|
-
# just +to_s(16)+. However, when zero-padding is required, it is
|
10
|
-
# ~230% faster than +sprintf("%0#{width}x", self)+, and ~30% faster
|
11
|
-
# than +sprintf(FIXED_FORMAT_STRING, self)+.
|
12
|
-
#
|
13
8
|
# @param [Integer] width desired width of the zero-padded string
|
14
9
|
# @return [String] hexadecimal string
|
15
|
-
def to_hex(width =
|
16
|
-
|
17
|
-
width ? h.rjust(width, '0'.freeze) : h
|
10
|
+
def to_hex(width = 0)
|
11
|
+
width > 1 ? self.to_s(16).rjust(width, '0'.freeze) : self.to_s(16)
|
18
12
|
end
|
19
13
|
|
20
14
|
end
|
@@ -1,4 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
require_relative 'string/after'
|
2
|
+
require_relative 'string/after_last'
|
3
|
+
require_relative 'string/before'
|
4
|
+
require_relative 'string/before_last'
|
5
|
+
require_relative 'string/between'
|
6
|
+
require_relative 'string/drop'
|
7
|
+
require_relative 'string/first'
|
8
|
+
require_relative 'string/from'
|
9
|
+
require_relative 'string/last'
|
10
|
+
require_relative 'string/lchomp'
|
11
|
+
require_relative 'string/prefix'
|
12
|
+
require_relative 'string/suffix'
|
13
|
+
require_relative 'string/to'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
# Searches for the first occurrence of a delimiter, and returns the
|
4
|
+
# portion of the string after that. If the delimiter is not found,
|
5
|
+
# returns nil. Equivalent to <code>split(delim, 2)[1]</code> for
|
6
|
+
# non-empty delimiters.
|
7
|
+
#
|
8
|
+
# @param [String] delim delimiter to search for
|
9
|
+
# @return [String] portion of the string after the first +delim+
|
10
|
+
def after(delim)
|
11
|
+
i = self.index(delim)
|
12
|
+
i && self[i + delim.length, self.length]
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
# Searches for the last occurrence of a delimiter, and returns the
|
4
|
+
# portion of the string after that. If the delimiter is not found,
|
5
|
+
# returns nil. Equivalent to <code>split(delim, -1).drop(1)[-1]</code>.
|
6
|
+
#
|
7
|
+
# @param [String] delim delimiter to search for
|
8
|
+
# @return [String] portion of the string after the last +delim+
|
9
|
+
def after_last(delim)
|
10
|
+
i = self.rindex(delim)
|
11
|
+
i && self[i + delim.length, self.length]
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
# Searches for the first occurrence of a delimiter, and returns the
|
4
|
+
# portion of the string before that. If the delimiter is not found,
|
5
|
+
# returns a copy of the original string. Equivalent to
|
6
|
+
# <code>split(delim, 2)[0]</code> for non-empty delimiters.
|
7
|
+
#
|
8
|
+
# @param [String] delim delimiter to search for
|
9
|
+
# @return [String] portion of the string before the first +delim+
|
10
|
+
def before(delim)
|
11
|
+
self[0, self.index(delim) || self.length]
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
# Searches for the last occurrence of a delimiter, and returns the
|
4
|
+
# portion of the string before that. If the delimiter is not found,
|
5
|
+
# returns a copy of the original string. Equivalent to
|
6
|
+
# <code>split(delim, -1)[0..-2].join(delim)</code> for existent
|
7
|
+
# delimiters.
|
8
|
+
#
|
9
|
+
# @param [String] delim delimiter to search for
|
10
|
+
# @return [String] portion of the string before the last +delim+
|
11
|
+
def before_last(delim)
|
12
|
+
self[0, self.rindex(delim) || self.length]
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
# Returns the portion of the string between the first occurrences of
|
4
|
+
# an opening and a closing delimiter. If either delimiter is not
|
5
|
+
# found, returns nil.
|
6
|
+
#
|
7
|
+
# @param [String] open opening delimiter
|
8
|
+
# @param [String] close closing delimiter
|
9
|
+
# @return [String] portion of the string between the delimiters
|
10
|
+
def between(open, close)
|
11
|
+
i = self.index(open)
|
12
|
+
j = self.index(close, i + 1) if i
|
13
|
+
j && self[i + 1, j - i - 1]
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
# This replaces Active Support's +String#first+, but it returns an
|
4
|
+
# empty string when given a negative +limit+ argument, whereas Active
|
5
|
+
# Support's +String#first+ removes +limit.abs+ characters from the
|
6
|
+
# end of the string. Returning an empty string makes more sense if
|
7
|
+
# you interpret +first+ as "keep upto +limit+ characters." At most, a
|
8
|
+
# negative +limit+ should *keep* that many characters from the end of
|
9
|
+
# the string, rather than *remove* that many characters (but returning
|
10
|
+
# an empty string is a good conservative choice).
|
11
|
+
#
|
12
|
+
# This method is also faster.
|
13
|
+
def first(limit = 1)
|
14
|
+
self[0, limit] || ''
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
# This replaces Active Support's +String#last+, but it returns an
|
4
|
+
# empty string when given a negative +limit+ argument, whereas Active
|
5
|
+
# Support's +String#last+ removes +limit.abs+ characters from the
|
6
|
+
# beginning of the string. Returning an empty string makes more sense
|
7
|
+
# if you interpret +last+ as "keep upto +limit+ characters." At most,
|
8
|
+
# a negative +limit+ should *keep* that many characters from the
|
9
|
+
# beginning of the string, rather than *remove* that many characters
|
10
|
+
# (but returning an empty string is a good conservative choice). Also
|
11
|
+
# see +String#first+.
|
12
|
+
#
|
13
|
+
# This method is also faster.
|
14
|
+
def last(limit = 1)
|
15
|
+
limit < 0 ? '' : (self[-limit, limit] || self.dup)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
# Removes the beginning of the string if that portion matches the
|
4
|
+
# argument. Otherwise returns a duplicate of the string. Like
|
5
|
+
# String#chomp, but operates on the left side (beginning) of the
|
6
|
+
# string.
|
7
|
+
#
|
8
|
+
# Also see https://bugs.ruby-lang.org/issues/10574
|
9
|
+
#
|
10
|
+
# @param [String] head substring to match and remove
|
11
|
+
# @return [String] chomped string
|
12
|
+
def lchomp(head)
|
13
|
+
self.start_with?(head) ? self[head.length, self.length] : self.dup
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
# Prepends a prefix to the string if the string does not already start
|
4
|
+
# with that prefix. Otherwise returns a duplicate of the string.
|
5
|
+
# Equivalent to <code>gsub(/^(?!fix)/, "fix")</code>.
|
6
|
+
#
|
7
|
+
# @param [String] fix prefix to prepend
|
8
|
+
# @return [String] prefixed string
|
9
|
+
def prefix(fix)
|
10
|
+
self.start_with?(fix) ? self.dup : "#{fix}#{self}"
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
# Appends a suffix to the string if the string does not already end
|
4
|
+
# with that suffix. Otherwise returns a duplicate of the string.
|
5
|
+
# Equivalent to <code>gsub(/(?<!fix)$/, "fix")</code>.
|
6
|
+
#
|
7
|
+
# @param [String] fix suffix to append
|
8
|
+
# @return [String] suffixed string
|
9
|
+
def suffix(fix)
|
10
|
+
self.end_with?(fix) ? self.dup : "#{self}#{fix}"
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
data/lib/casual_support/time.rb
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
|
1
|
+
require_relative 'time/to_hms'
|
2
|
+
require_relative 'time/to_ymd'
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Time
|
2
|
+
|
3
|
+
# Formats time as "HH:MM:SS" (e.g. "23:59:59"). Equivalent to
|
4
|
+
# <code>strftime("%H:%M:%S")</code>, but faster.
|
5
|
+
#
|
6
|
+
# @return [String] the time formatted as "HH:MM:SS"
|
7
|
+
def to_hms
|
8
|
+
# Date#strftime appears to be **much** faster than Time#strftime
|
9
|
+
# (nearly 3x faster!). If Time#strftime becomes optimized to that
|
10
|
+
# level in the future, it should be used instead of sprintf.
|
11
|
+
sprintf('%02d:%02d:%02d'.freeze, hour, min, sec)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Time
|
2
|
+
|
3
|
+
# Formats time as "YYYY-MM-DD" (e.g. "1999-12-31"). Equivalent to
|
4
|
+
# <code>strftime("%Y-%m-%d")</code>, but faster.
|
5
|
+
#
|
6
|
+
# @return [String] the time formatted as "YYYY-MM-DD"
|
7
|
+
def to_ymd
|
8
|
+
# Date#strftime appears to be **much** faster than Time#strftime
|
9
|
+
# (nearly 3x faster!). If Time#strftime becomes optimized to that
|
10
|
+
# level in the future, it should be used instead of sprintf.
|
11
|
+
sprintf('%04d-%02d-%02d'.freeze, year, month, day)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|