invoca-utils 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/.ruby-version +1 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +56 -0
- data/Rakefile +8 -11
- data/invoca-utils.gemspec +1 -1
- data/lib/invoca/utils/diff.rb +3 -3
- data/lib/invoca/utils/guaranteed_utf8_string.rb +68 -0
- data/lib/invoca/utils/http.rb +45 -0
- data/lib/invoca/utils/map_compact.rb +10 -0
- data/lib/invoca/utils/min_max.rb +9 -0
- data/lib/invoca/utils/stable_sort.rb +23 -0
- data/lib/invoca/utils/time.rb +34 -0
- data/lib/invoca/utils/version.rb +1 -1
- data/lib/invoca/utils.rb +7 -3
- data/test/unit/guaranteed_utf8_string_test.rb +116 -0
- data/test/unit/map_compact_test.rb +23 -0
- data/test/unit/stable_sort_test.rb +52 -0
- data/test/unit/time_calculations_test.rb +38 -0
- data/test/unit/utils_test.rb +2 -2
- metadata +33 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9af5982666a515cac52ec601dcc30bb8be8b473a
|
4
|
+
data.tar.gz: ab9b463b80311d295136c72b5df683b959e03579
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0b807a493e7bedc3eca0901d3276723d8cadc91cd3a67a2b31b009695f0be4ffd16562254802a9aab4526b29bd463da17b942400e197a122d08a41e0c37b8c8c
|
7
|
+
data.tar.gz: 4fcf0da07ac921a2410271dd84c94599ca5ee8893be9db532e41970141fdd35172459f843a32c8cabbc2887b13b4d039991059322a43359090565cbf34a603ea
|
data/.gitignore
CHANGED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.4.2
|
data/Gemfile
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
invoca-utils (0.0.3)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
activesupport (5.1.4)
|
10
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
11
|
+
i18n (~> 0.7)
|
12
|
+
minitest (~> 5.1)
|
13
|
+
tzinfo (~> 1.1)
|
14
|
+
coderay (1.1.2)
|
15
|
+
concurrent-ruby (1.0.5)
|
16
|
+
hoe (3.16.2)
|
17
|
+
rake (>= 0.8, < 13.0)
|
18
|
+
i18n (0.9.1)
|
19
|
+
concurrent-ruby (~> 1.0)
|
20
|
+
method_source (0.9.0)
|
21
|
+
minitest (5.11.1)
|
22
|
+
pry (0.11.3)
|
23
|
+
coderay (~> 1.1.0)
|
24
|
+
method_source (~> 0.9.0)
|
25
|
+
rake (12.3.0)
|
26
|
+
rr (1.1.2)
|
27
|
+
ruby-prof (0.17.0)
|
28
|
+
shoulda (3.5.0)
|
29
|
+
shoulda-context (~> 1.0, >= 1.0.1)
|
30
|
+
shoulda-matchers (>= 1.4.1, < 3.0)
|
31
|
+
shoulda-context (1.2.2)
|
32
|
+
shoulda-matchers (2.8.0)
|
33
|
+
activesupport (>= 3.0.0)
|
34
|
+
test-unit (1.2.3)
|
35
|
+
hoe (>= 1.5.1)
|
36
|
+
thread_safe (0.3.6)
|
37
|
+
tzinfo (1.2.4)
|
38
|
+
thread_safe (~> 0.1)
|
39
|
+
|
40
|
+
PLATFORMS
|
41
|
+
ruby
|
42
|
+
|
43
|
+
DEPENDENCIES
|
44
|
+
bundler (~> 1.6)
|
45
|
+
invoca-utils!
|
46
|
+
minitest
|
47
|
+
pry
|
48
|
+
rake
|
49
|
+
rr (= 1.1.2)
|
50
|
+
ruby-prof
|
51
|
+
shoulda (= 3.5.0)
|
52
|
+
test-unit (= 1.2.3)
|
53
|
+
tzinfo
|
54
|
+
|
55
|
+
BUNDLED WITH
|
56
|
+
1.16.0
|
data/Rakefile
CHANGED
@@ -2,17 +2,14 @@
|
|
2
2
|
require "bundler/gem_tasks"
|
3
3
|
require 'rake/testtask'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
t.pattern = 'test/unit/**/*_test.rb'
|
11
|
-
t.verbose = true
|
12
|
-
end
|
13
|
-
Rake::Task['test:unit'].comment = "Run the unit tests"
|
14
|
-
|
5
|
+
Rake::TestTask.new(:test) do |t|
|
6
|
+
t.libs << 'lib'
|
7
|
+
t.libs << 'test'
|
8
|
+
t.pattern = 'test/**/*_test.rb'
|
9
|
+
t.verbose = false
|
15
10
|
end
|
16
11
|
|
17
|
-
task :
|
12
|
+
task default: :test
|
13
|
+
|
14
|
+
task :default => 'test'
|
18
15
|
|
data/invoca-utils.gemspec
CHANGED
@@ -20,11 +20,11 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.6"
|
22
22
|
spec.add_development_dependency "rake"
|
23
|
-
|
24
23
|
spec.add_development_dependency "test-unit", "= 1.2.3"
|
25
24
|
spec.add_development_dependency "rr", "=1.1.2"
|
26
25
|
spec.add_development_dependency "shoulda", "= 3.5.0"
|
27
26
|
spec.add_development_dependency "pry"
|
28
27
|
spec.add_development_dependency "ruby-prof"
|
29
28
|
spec.add_development_dependency "minitest"
|
29
|
+
spec.add_development_dependency "tzinfo"
|
30
30
|
end
|
data/lib/invoca/utils/diff.rb
CHANGED
@@ -87,7 +87,7 @@ class Diff
|
|
87
87
|
result << " #{format arg}\n" unless arg.nil? || options[:short_description]
|
88
88
|
end
|
89
89
|
if curr_diff && curr_diff[1].first == index
|
90
|
-
verb,
|
90
|
+
verb, _a_range, _b_range, del, add = curr_diff
|
91
91
|
result <<
|
92
92
|
case verb
|
93
93
|
when 'd'
|
@@ -96,8 +96,8 @@ class Diff
|
|
96
96
|
add.map { |t| "+ #{format t}\n"}.join +
|
97
97
|
(arg.nil? ? '' : " #{format arg}\n")
|
98
98
|
when 'c'
|
99
|
-
del.map_with_index { |t,
|
100
|
-
add.
|
99
|
+
del.map_with_index { |t, del_index| "- #{format t}\n#{nested_compare(del, add, del_index)}" }.join +
|
100
|
+
add.map { |t| "+ #{format t}\n" }.join
|
101
101
|
end
|
102
102
|
end
|
103
103
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This class expects to be initialized with a string and guarantees that the output of the to_string method is in UTF-8 format and fits in 3 bytes/char or less.
|
4
|
+
module Invoca
|
5
|
+
module Utils
|
6
|
+
class GuaranteedUTF8String
|
7
|
+
def initialize(string)
|
8
|
+
if string.is_a?(String) ||
|
9
|
+
(string.respond_to?(:to_s) &&
|
10
|
+
string.method(:to_s).owner != Kernel) # the lame .to_s from Kernel just calls .inspect :(
|
11
|
+
@string = string.to_s
|
12
|
+
else
|
13
|
+
raise ArgumentError, "#{self.class} must be initialized with a string or an object with a non-Kernel .to_s method but instead was #{string.class} #{string.inspect}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_string
|
18
|
+
@to_string ||= normalize_string(@string)
|
19
|
+
end
|
20
|
+
|
21
|
+
alias_method :to_s, :to_string
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
# chosen because this is a 1-byte ASCII character that is not used in any of the popular escaping systems: XML, HTML, HTTP URIs, HTTP Form Post, JSON
|
26
|
+
REPLACE_CHARACTER = '~' unless defined?(REPLACE_CHARACTER)
|
27
|
+
|
28
|
+
def normalize_string(str)
|
29
|
+
str = @string.dup
|
30
|
+
str.force_encoding('UTF-8')
|
31
|
+
if !str.valid_encoding?
|
32
|
+
cp1252_to_utf_8(str)
|
33
|
+
end
|
34
|
+
normalize_newlines(str)
|
35
|
+
remove_bom(str)
|
36
|
+
replace_unicode_beyond_ffff(str)
|
37
|
+
str
|
38
|
+
end
|
39
|
+
|
40
|
+
def normalize_newlines(str)
|
41
|
+
str.gsub!(/ \r\n | \r | \n /x, "\n")
|
42
|
+
end
|
43
|
+
|
44
|
+
def cp1252_to_utf_8(str)
|
45
|
+
str.force_encoding('CP1252')
|
46
|
+
str.encode!(
|
47
|
+
'UTF-8',
|
48
|
+
replace: REPLACE_CHARACTER,
|
49
|
+
undef: :replace,
|
50
|
+
invalid: :replace
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
def remove_bom(str)
|
55
|
+
str.sub!(/\A \xEF\xBB\xBF/x, '')
|
56
|
+
end
|
57
|
+
|
58
|
+
# Note MySQL can only store Unicode up to code point U+FFFF in the standard mb3 storage type. There is an option to use mb4 which
|
59
|
+
# is needed to hold the code points above that (including emoji) but we haven't enabled that on any columns yet since
|
60
|
+
# it would take a data migration and didn't seem that important.
|
61
|
+
|
62
|
+
def replace_unicode_beyond_ffff(str)
|
63
|
+
str.gsub!(/[^\u{0}-\u{ffff}]/x, REPLACE_CHARACTER)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
if RUBY_VERSION == '1.8.7'
|
4
|
+
module ::Net #:nodoc:
|
5
|
+
class HTTP < Protocol
|
6
|
+
def connect
|
7
|
+
D "opening connection to #{conn_address()}..."
|
8
|
+
s = timeout(@open_timeout) { TCPSocket.open(conn_address(), conn_port()) }
|
9
|
+
D "opened"
|
10
|
+
if use_ssl?
|
11
|
+
unless @ssl_context.verify_mode
|
12
|
+
warn "warning: peer certificate won't be verified in this SSL session"
|
13
|
+
@ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
14
|
+
end
|
15
|
+
s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
|
16
|
+
s.sync_close = true
|
17
|
+
end
|
18
|
+
@socket = BufferedIO.new(s)
|
19
|
+
@socket.read_timeout = @read_timeout
|
20
|
+
@socket.debug_output = @debug_output
|
21
|
+
if use_ssl?
|
22
|
+
if proxy?
|
23
|
+
@socket.writeline sprintf('CONNECT %s:%s HTTP/%s',
|
24
|
+
@address, @port, HTTPVersion)
|
25
|
+
@socket.writeline "Host: #{@address}:#{@port}"
|
26
|
+
if proxy_user
|
27
|
+
credential = ["#{proxy_user}:#{proxy_pass}"].pack('m')
|
28
|
+
credential.delete!("\r\n")
|
29
|
+
@socket.writeline "Proxy-Authorization: Basic #{credential}"
|
30
|
+
end
|
31
|
+
@socket.writeline ''
|
32
|
+
HTTPResponse.read_new(@socket).value
|
33
|
+
end
|
34
|
+
# NOTE: Change here. This was just s.connect, now we have added a timeout.
|
35
|
+
timeout(@open_timeout) { s.connect }
|
36
|
+
if @ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE
|
37
|
+
s.post_connection_check(@address)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
on_connect
|
41
|
+
end
|
42
|
+
private :connect
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ::Enumerable
|
2
|
+
|
3
|
+
# A stable sort will preserve the original order of two elements if their sort keys are identical.
|
4
|
+
|
5
|
+
def stable_sort
|
6
|
+
n = -1
|
7
|
+
if block_given?
|
8
|
+
collect {|x| n += 1; [x, n]
|
9
|
+
}.sort! {|a, b|
|
10
|
+
c = yield a[0], b[0]
|
11
|
+
if c.nonzero? then c else a[1] <=> b[1] end
|
12
|
+
}.collect! {|x| x[0]}
|
13
|
+
else
|
14
|
+
sort_by {|x| n += 1; [x, n]}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def stable_sort_by
|
19
|
+
block_given? or return enum_for(:stable_sort_by)
|
20
|
+
n = -1
|
21
|
+
sort_by {|x| n += 1; [(yield x), n]}
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Invoca ::Time extensions
|
2
|
+
class ::Time
|
3
|
+
def to_ms
|
4
|
+
@to_ms ||= (self.to_f * 1000).to_i
|
5
|
+
end
|
6
|
+
|
7
|
+
#rfc3339ms is like rfc3339 but with milliseconds
|
8
|
+
if RUBY_VERSION < "1.9.3"
|
9
|
+
def rfc3339ms
|
10
|
+
strftime("%Y-%m-%dT%H:%M:%S.#{ms_for_3339}%z")
|
11
|
+
end
|
12
|
+
|
13
|
+
def ms_for_3339
|
14
|
+
@ms_for_3339 ||= ("%03.3d" % (self.to_ms % 1000))
|
15
|
+
end
|
16
|
+
private :ms_for_3339
|
17
|
+
else
|
18
|
+
def rfc3339ms
|
19
|
+
strftime("%Y-%m-%dT%H:%M:%S.%L%z")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def beginning_of_hour
|
24
|
+
change(:min => 0, :sec => 0, :usec => 0)
|
25
|
+
end
|
26
|
+
|
27
|
+
def end_of_day_whole_sec # usec can be bad because it isn't preserved by MySQL
|
28
|
+
change(:hour => 23, :min => 59, :sec => 59, :usec => 0)
|
29
|
+
end
|
30
|
+
|
31
|
+
def whole_sec
|
32
|
+
change(:usec => 0)
|
33
|
+
end
|
34
|
+
end
|
data/lib/invoca/utils/version.rb
CHANGED
data/lib/invoca/utils.rb
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
-
require "invoca/utils/version"
|
2
|
-
|
3
1
|
require "invoca/utils/diff"
|
2
|
+
require "invoca/utils/http"
|
3
|
+
require "invoca/utils/map_compact"
|
4
|
+
require "invoca/utils/min_max"
|
5
|
+
require "invoca/utils/stable_sort"
|
6
|
+
require "invoca/utils/time"
|
7
|
+
require "invoca/utils/guaranteed_utf8_string"
|
8
|
+
require "invoca/utils/version"
|
4
9
|
|
5
10
|
module Invoca
|
6
11
|
module Utils
|
7
|
-
|
8
12
|
end
|
9
13
|
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../test_helper'
|
4
|
+
|
5
|
+
class GuaranteedUTF8StringTest < Minitest::Test
|
6
|
+
class HasNoTo_sMethod
|
7
|
+
undef :to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
class BasicObjectWithKernelMethods
|
11
|
+
end
|
12
|
+
|
13
|
+
class ConvertibleToString
|
14
|
+
attr_reader :to_s
|
15
|
+
|
16
|
+
def initialize(string)
|
17
|
+
@to_s = string
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
should "raise an error if initialized with an object with no to_s method" do
|
22
|
+
assert_raises ArgumentError, /GuaranteedUTF8String must be initialized with a string or an object with a non-Kernel \.to_s method but instead was GuaranteedUTF8StringTest::HasNoTo_sMethod/ do
|
23
|
+
Invoca::Utils::GuaranteedUTF8String.new(HasNoTo_sMethod.new)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
should "raise an error if initialized with a basic Ruby object" do
|
28
|
+
assert_raises ArgumentError, /GuaranteedUTF8String must be initialized with a string or an object with a non-Kernel \.to_s method but instead was GuaranteedUTF8StringTest::BasicObjectWithKernelMethods/ do
|
29
|
+
Invoca::Utils::GuaranteedUTF8String.new(BasicObjectWithKernelMethods.new)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
should "convert to a string with to_s if possible" do
|
34
|
+
result = Invoca::Utils::GuaranteedUTF8String.new(ConvertibleToString.new("test string"))
|
35
|
+
assert_equal "test string", result.to_string
|
36
|
+
end
|
37
|
+
|
38
|
+
context "#to_string" do
|
39
|
+
should "not mutate the original string" do
|
40
|
+
ascii_string = "new string".encode("ASCII")
|
41
|
+
utf8_string_instance = Invoca::Utils::GuaranteedUTF8String.new(ascii_string)
|
42
|
+
encoded_string = utf8_string_instance.to_string
|
43
|
+
|
44
|
+
assert_equal ascii_string, encoded_string
|
45
|
+
assert_equal Encoding::ASCII, ascii_string.encoding
|
46
|
+
assert_equal Encoding::UTF_8, encoded_string.encoding
|
47
|
+
end
|
48
|
+
|
49
|
+
should "return UTF-8 encoded string" do
|
50
|
+
original_string = "this,is,a,valid,utf-8,csv,string\none,two,three,four,five,six,seven\n"
|
51
|
+
|
52
|
+
encoded_string = Invoca::Utils::GuaranteedUTF8String.new(original_string).to_string
|
53
|
+
|
54
|
+
assert_equal original_string, encoded_string
|
55
|
+
assert_equal Encoding::UTF_8, encoded_string.encoding
|
56
|
+
end
|
57
|
+
|
58
|
+
should "return UTF-8 encoded string without BOM" do
|
59
|
+
original_string = "\xEF\xBB\xBFthis,is,a,valid,utf-8,csv,string\none,two,three,four,five,six,seven\n"
|
60
|
+
|
61
|
+
encoded_string = Invoca::Utils::GuaranteedUTF8String.new(original_string).to_string
|
62
|
+
|
63
|
+
assert_equal "this,is,a,valid,utf-8,csv,string\none,two,three,four,five,six,seven\n", encoded_string
|
64
|
+
assert_equal Encoding::UTF_8, encoded_string.encoding
|
65
|
+
end
|
66
|
+
|
67
|
+
should "return UTF-8 encoded string using to_s alias" do
|
68
|
+
original_string = "this,is,a,valid,utf-8,csv,string\none,two,three,four,five,six,seven\n"
|
69
|
+
|
70
|
+
encoded_string = Invoca::Utils::GuaranteedUTF8String.new(original_string).to_s
|
71
|
+
|
72
|
+
assert_equal original_string, encoded_string
|
73
|
+
assert_equal Encoding::UTF_8, encoded_string.encoding
|
74
|
+
end
|
75
|
+
|
76
|
+
should "return UTF-8 encoded string after falling back to CP1252 encoding" do
|
77
|
+
string = "This,is,NOT,a,valid,utf-8,csv,string\r\none,two,three,four,\x81five\xF6,six,seven,eight\n"
|
78
|
+
expected_string = "This,is,NOT,a,valid,utf-8,csv,string\none,two,three,four,~fiveö,six,seven,eight\n"
|
79
|
+
|
80
|
+
encoded_string = Invoca::Utils::GuaranteedUTF8String.new(string).to_string
|
81
|
+
|
82
|
+
assert_equal expected_string, encoded_string
|
83
|
+
assert_equal Encoding::UTF_8, encoded_string.encoding
|
84
|
+
end
|
85
|
+
|
86
|
+
should "return UTF-8 encoded string with normalized return chars" do
|
87
|
+
string = "This string\n\n\n has line feeds\ncarriage\r\r returns\rand Windows\r\n\r\n new line chars\r\nend of \n\r\r\r\nstring"
|
88
|
+
expected_string = "This string\n\n\n has line feeds\ncarriage\n\n returns\nand Windows\n\n new line chars\nend of \n\n\n\nstring"
|
89
|
+
|
90
|
+
encoded_string = Invoca::Utils::GuaranteedUTF8String.new(string).to_string
|
91
|
+
|
92
|
+
assert_equal expected_string, encoded_string
|
93
|
+
assert_equal Encoding::UTF_8, encoded_string.encoding
|
94
|
+
end
|
95
|
+
|
96
|
+
should "encode all 255 UTF-8 characters, returning ~ when the character isn't mapped in CP1252" do
|
97
|
+
all_8_bit_characters = (1..255).map { |char| char.chr }.join
|
98
|
+
|
99
|
+
final_utf_8_string = Invoca::Utils::GuaranteedUTF8String.new(all_8_bit_characters.dup).to_s
|
100
|
+
expected_string = "\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000A\u000B\u000C\u000A\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F !\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007F€~‚ƒ„…†‡ˆ‰Š‹Œ~Ž~~‘’“”•–—˜™š›œ~žŸ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ"
|
101
|
+
|
102
|
+
assert_equal expected_string, final_utf_8_string
|
103
|
+
end
|
104
|
+
|
105
|
+
should "consider UTF-8 code points that take > 3 bytes (above U+FFFF) to be invalid (since MySQL can't store them unless column is declared mb4) and encode them as ~" do
|
106
|
+
string = "This string has some ✓ valid UTF-8 but also some 😹 emoji \xf0\x9f\x98\xb9 that are > U+FFFF"
|
107
|
+
expected_string = "This string has some ✓ valid UTF-8 but also some ~ emoji ~ that are > U+FFFF"
|
108
|
+
|
109
|
+
encoded_string = Invoca::Utils::GuaranteedUTF8String.new(string).to_string
|
110
|
+
|
111
|
+
assert_equal expected_string, encoded_string
|
112
|
+
assert_equal Encoding::UTF_8, encoded_string.encoding
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
class MapCompactTest < Minitest::Test
|
4
|
+
should "map_compact" do
|
5
|
+
assert_equal [1, 9], [1, 2, nil, 3, 4].map_compact { |item| item**2 if (nil == item ? nil : item.odd?) }
|
6
|
+
end
|
7
|
+
|
8
|
+
should "map_compact to empty if nothing matches" do
|
9
|
+
assert_equal [], {:a => 'aaa', :b => 'bbb'}.map_compact { |key, value| value if key == :c }
|
10
|
+
end
|
11
|
+
|
12
|
+
should "map_compact a hash" do
|
13
|
+
assert_equal ['bbb'], {:a => 'aaa', :b => 'bbb'}.map_compact { |key, value| value if key == :b }
|
14
|
+
end
|
15
|
+
|
16
|
+
should "map_compact empty collection" do
|
17
|
+
assert_equal [], [].map_compact { |item| true }
|
18
|
+
end
|
19
|
+
|
20
|
+
should "not map_compact false" do
|
21
|
+
assert_equal [false], [nil, false].map_compact { |a| a }
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
class StableSortTest < Minitest::Test
|
4
|
+
context "#stable_sort_by" do
|
5
|
+
should "preserve the original order if all sort the same" do
|
6
|
+
list_to_sort = [:b, :d, :c, :a, :e, :f]
|
7
|
+
|
8
|
+
assert_equal list_to_sort, list_to_sort.stable_sort_by { |c| 0 }
|
9
|
+
end
|
10
|
+
|
11
|
+
should "order by keys first and then position" do
|
12
|
+
list_to_sort = [:b, :d, :c, :a, :e, :f]
|
13
|
+
order = [:a, :b, :c]
|
14
|
+
|
15
|
+
result = list_to_sort.stable_sort_by { |c| order.index(c) || order.length }
|
16
|
+
assert_equal [:a, :b, :c, :d, :e, :f], result
|
17
|
+
end
|
18
|
+
|
19
|
+
should "order by keys only if needed" do
|
20
|
+
list_to_sort = [:b, :d, :c, :a, :e, :f]
|
21
|
+
result = list_to_sort.stable_sort_by { |c| c.to_s }
|
22
|
+
assert_equal [:a, :b, :c, :d, :e, :f], result
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "stable_sort" do
|
27
|
+
should "preserve the original order if all sort the same" do
|
28
|
+
list_to_sort = [:b, :d, :c, :a, :e, :f]
|
29
|
+
|
30
|
+
assert_equal list_to_sort, list_to_sort.stable_sort { |first, second| 0 }
|
31
|
+
end
|
32
|
+
|
33
|
+
should "order by keys first and then position" do
|
34
|
+
list_to_sort = [:b, :d, :c, :a, :e, :f]
|
35
|
+
order = [:a, :b, :c]
|
36
|
+
|
37
|
+
result = list_to_sort.stable_sort do |first, second|
|
38
|
+
first_pos = order.index(first) || order.length
|
39
|
+
second_pos = order.index(second) || order.length
|
40
|
+
first_pos <=> second_pos
|
41
|
+
end
|
42
|
+
|
43
|
+
assert_equal [:a, :b, :c, :d, :e, :f], result
|
44
|
+
end
|
45
|
+
|
46
|
+
should "order by keys only if needed" do
|
47
|
+
list_to_sort = [:b, :d, :c, :a, :e, :f]
|
48
|
+
result = list_to_sort.stable_sort{ |first, second| first.to_s <=> second.to_s }
|
49
|
+
assert_equal [:a, :b, :c, :d, :e, :f], result
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
require 'active_support/all'
|
3
|
+
|
4
|
+
class TimeCalculationsTest < Minitest::Test
|
5
|
+
context "beginning_of_hour" do
|
6
|
+
Time.zone = 'Pacific Time (US & Canada)'
|
7
|
+
[
|
8
|
+
Time.now,
|
9
|
+
Time.zone.now,
|
10
|
+
Time.local(2009),
|
11
|
+
Time.local(2009,3,4,5),
|
12
|
+
Time.local(2001,12,31,23,59),
|
13
|
+
Time.local(1970,1,1)
|
14
|
+
].each_with_index do |time, index|
|
15
|
+
should "give back a time with no minutes, seconds, or msec: #{time} (#{index})" do
|
16
|
+
t = time.beginning_of_hour
|
17
|
+
assert_equal t.year, time.year
|
18
|
+
assert_equal t.month, time.month
|
19
|
+
assert_equal t.day, time.day
|
20
|
+
assert_equal t.hour, time.hour
|
21
|
+
assert_equal 0, t.min
|
22
|
+
assert_equal 0, t.sec
|
23
|
+
assert_equal 0, t.usec
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "end_of_day_whole_sec" do
|
29
|
+
should "return the end of day with whole_sec" do
|
30
|
+
t = Time.now
|
31
|
+
end_of_day = t.end_of_day
|
32
|
+
end_whole_sec = t.end_of_day_whole_sec
|
33
|
+
assert_equal 0.0, end_whole_sec.usec
|
34
|
+
assert_equal end_of_day.to_i, end_whole_sec.to_i
|
35
|
+
assert_equal end_of_day.sec, end_whole_sec.sec
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/test/unit/utils_test.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: invoca-utils
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cary Penniman
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-09-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -122,6 +122,20 @@ dependencies:
|
|
122
122
|
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: tzinfo
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
125
139
|
description: A public collection of helpers used in multiple projects
|
126
140
|
email:
|
127
141
|
- cpenniman@invoca.com
|
@@ -130,15 +144,27 @@ extensions: []
|
|
130
144
|
extra_rdoc_files: []
|
131
145
|
files:
|
132
146
|
- ".gitignore"
|
147
|
+
- ".ruby-version"
|
133
148
|
- Gemfile
|
149
|
+
- Gemfile.lock
|
134
150
|
- LICENSE.txt
|
135
151
|
- README.md
|
136
152
|
- Rakefile
|
137
153
|
- invoca-utils.gemspec
|
138
154
|
- lib/invoca/utils.rb
|
139
155
|
- lib/invoca/utils/diff.rb
|
156
|
+
- lib/invoca/utils/guaranteed_utf8_string.rb
|
157
|
+
- lib/invoca/utils/http.rb
|
158
|
+
- lib/invoca/utils/map_compact.rb
|
159
|
+
- lib/invoca/utils/min_max.rb
|
160
|
+
- lib/invoca/utils/stable_sort.rb
|
161
|
+
- lib/invoca/utils/time.rb
|
140
162
|
- lib/invoca/utils/version.rb
|
141
163
|
- test/test_helper.rb
|
164
|
+
- test/unit/guaranteed_utf8_string_test.rb
|
165
|
+
- test/unit/map_compact_test.rb
|
166
|
+
- test/unit/stable_sort_test.rb
|
167
|
+
- test/unit/time_calculations_test.rb
|
142
168
|
- test/unit/utils_test.rb
|
143
169
|
homepage: ''
|
144
170
|
licenses:
|
@@ -160,10 +186,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
160
186
|
version: '0'
|
161
187
|
requirements: []
|
162
188
|
rubyforge_project:
|
163
|
-
rubygems_version: 2.
|
189
|
+
rubygems_version: 2.6.13
|
164
190
|
signing_key:
|
165
191
|
specification_version: 4
|
166
192
|
summary: A public collection of helpers used in multiple projects
|
167
193
|
test_files:
|
168
194
|
- test/test_helper.rb
|
195
|
+
- test/unit/guaranteed_utf8_string_test.rb
|
196
|
+
- test/unit/map_compact_test.rb
|
197
|
+
- test/unit/stable_sort_test.rb
|
198
|
+
- test/unit/time_calculations_test.rb
|
169
199
|
- test/unit/utils_test.rb
|