invoca-utils 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 926143286cf40283408cd86732347339453d12a671c2e1539f01e391cef84ed4
4
- data.tar.gz: b4114b43131585610f6e875680895e1be15fe68e164a0a8904ddec46b59e58cf
3
+ metadata.gz: 54dcad50905bf9c0d48905b88e563c6418ea4bc852e4f85d4cd892e2b2031096
4
+ data.tar.gz: 592dde85e812312a5fb5ff67d34da1d5a0127f0c2c2f5f60538baab3c63d32ff
5
5
  SHA512:
6
- metadata.gz: 50a6cf86a1547385b1b7dabfce31f4a89d0156f872f7dde7b6e179afd6373f8b56cc6e4bfea3b383af02aaabb6567a096d4dfe9250a8e639a0f02c3d0535455f
7
- data.tar.gz: 2bcfc2fa9de854a2f78ba03a5bd9814fc921c9ab668ca0660491b14679e81536a9e4c61cb6e4b8f00f88ddb609a891956f02094de64e48efbe0411fdc4afbeff
6
+ metadata.gz: 6fac4beb8eef9b3a4ebc3615cb7711c9134e401e34ba26a2d0012b89c7962ca19440b2ceb2e0fafd5aaafcd4576717d10fddd276c4583858ffc725904194464a
7
+ data.tar.gz: c312101bd66d62f9c145610be64a8e75ec931387d4dc33f581885dc5707ff7565e474fd618ddbf569ed9091a591d0f2e0a164b7899ffe311b889c62fbc5a7d37
@@ -4,6 +4,12 @@ Inspired by [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
4
4
 
5
5
  Note: This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.4.0] - 2020-06-09
8
+ ### Added
9
+ - Added `Invoca::Utils.retry_on_exception`.
10
+ - Added `Invoca::Utils::GuaranteedUTF8String.normalize_all_strings` to normalize
11
+ all strings found in a JSON doc of hashes, arrays, and values.
12
+
7
13
  ## [0.3.0] - 2020-04-28
8
14
  ### Added
9
15
  - Array::* operator changed to use alias_method instead of prepend to prevent infinite recursion when HoboSupport gem is present
@@ -17,5 +23,6 @@ Note: This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0
17
23
  - Enumerable::build_hash method ported from HoboSupport
18
24
  - Enumerable::* operator ported from HoboSupport
19
25
 
26
+ [0.4.0]: https://github.com/Invoca/invoca-utils/compare/v0.3.0...v0.4.0
20
27
  [0.3.0]: https://github.com/Invoca/invoca-utils/compare/v0.2.0...v0.3.0
21
28
  [0.2.0]: https://github.com/Invoca/invoca-utils/compare/v0.1.1...v0.2.0
data/Gemfile CHANGED
@@ -4,7 +4,7 @@ source 'https://rubygems.org'
4
4
 
5
5
  gemspec
6
6
 
7
- group :development do
7
+ source 'https://rubygems.org' do
8
8
  gem 'activesupport', '~> 4.2'
9
9
  gem 'minitest'
10
10
  gem 'minitest-reporters'
@@ -16,3 +16,7 @@ group :development do
16
16
  gem 'test-unit', '= 1.2.3'
17
17
  gem 'tzinfo'
18
18
  end
19
+
20
+ source 'https://gem.fury.io/invoca' do
21
+ gem 'test_overrides', '~> 0.13'
22
+ end
@@ -1,37 +1,38 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- invoca-utils (0.3.0)
4
+ invoca-utils (0.4.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
+ remote: https://gem.fury.io/invoca/
8
9
  specs:
9
- activesupport (4.2.11.1)
10
+ activesupport (4.2.11.3)
10
11
  i18n (~> 0.7)
11
12
  minitest (~> 5.1)
12
13
  thread_safe (~> 0.3, >= 0.3.4)
13
14
  tzinfo (~> 1.1)
14
15
  ansi (1.5.0)
15
16
  builder (3.2.4)
16
- coderay (1.1.2)
17
+ coderay (1.1.3)
17
18
  concurrent-ruby (1.1.6)
18
19
  hoe (3.22.1)
19
20
  rake (>= 0.8, < 15.0)
20
21
  i18n (0.9.5)
21
22
  concurrent-ruby (~> 1.0)
22
- method_source (0.9.0)
23
- minitest (5.14.0)
24
- minitest-reporters (1.1.14)
23
+ method_source (1.0.0)
24
+ minitest (5.14.1)
25
+ minitest-reporters (1.4.2)
25
26
  ansi
26
27
  builder
27
28
  minitest (>= 5.0)
28
29
  ruby-progressbar
29
- pry (0.11.3)
30
- coderay (~> 1.1.0)
31
- method_source (~> 0.9.0)
30
+ pry (0.13.1)
31
+ coderay (~> 1.1)
32
+ method_source (~> 1.0)
32
33
  rake (13.0.1)
33
34
  rr (1.1.2)
34
- ruby-prof (0.17.0)
35
+ ruby-prof (1.4.1)
35
36
  ruby-progressbar (1.10.1)
36
37
  shoulda (3.5.0)
37
38
  shoulda-context (~> 1.0, >= 1.0.1)
@@ -41,6 +42,7 @@ GEM
41
42
  activesupport (>= 3.0.0)
42
43
  test-unit (1.2.3)
43
44
  hoe (>= 1.5.1)
45
+ test_overrides (0.13.0)
44
46
  thread_safe (0.3.6)
45
47
  tzinfo (1.2.7)
46
48
  thread_safe (~> 0.1)
@@ -49,17 +51,18 @@ PLATFORMS
49
51
  ruby
50
52
 
51
53
  DEPENDENCIES
52
- activesupport (~> 4.2)
54
+ activesupport (~> 4.2)!
53
55
  invoca-utils!
54
- minitest
55
- minitest-reporters
56
- pry
57
- rake
58
- rr (= 1.1.2)
59
- ruby-prof
60
- shoulda (= 3.5.0)
61
- test-unit (= 1.2.3)
62
- tzinfo
56
+ minitest!
57
+ minitest-reporters!
58
+ pry!
59
+ rake!
60
+ rr (= 1.1.2)!
61
+ ruby-prof!
62
+ shoulda (= 3.5.0)!
63
+ test-unit (= 1.2.3)!
64
+ test_overrides (~> 0.13)!
65
+ tzinfo!
63
66
 
64
67
  BUNDLED WITH
65
68
  1.17.3
data/Rakefile CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  require "bundler/gem_tasks"
5
5
  require 'rake/testtask'
6
+ require 'rake_test_warning_false'
6
7
 
7
8
  task default: :test
8
9
 
@@ -1,4 +1,4 @@
1
- lib = File.expand_path('../lib', __FILE__)
1
+ lib = File.expand_path('lib', __dir__)
2
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
  require 'invoca/utils/version'
4
4
 
@@ -7,8 +7,7 @@ Gem::Specification.new do |spec|
7
7
  spec.version = Invoca::Utils::VERSION
8
8
  spec.authors = ["Invoca development"]
9
9
  spec.email = ["development@invoca.com"]
10
- spec.summary = %q{A public collection of helpers used in multiple projects}
11
- spec.description = %q{A public collection of helpers used in multiple projects}
10
+ spec.summary = "A public collection of helpers used in multiple projects"
12
11
  spec.homepage = ""
13
12
  spec.license = "MIT"
14
13
 
@@ -1,5 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ module Invoca
4
+ module Utils
5
+ end
6
+ end
7
+
3
8
  require "invoca/utils/module"
4
9
  require "invoca/utils/array"
5
10
  require "invoca/utils/enumerable"
@@ -11,14 +16,10 @@ require "invoca/utils/map_compact"
11
16
  require "invoca/utils/min_max"
12
17
  require "invoca/utils/stable_sort"
13
18
  require "invoca/utils/time"
19
+ require "invoca/utils/exceptions"
14
20
  require "invoca/utils/guaranteed_utf8_string"
15
21
  require "invoca/utils/version"
16
22
 
17
- module Invoca
18
- module Utils
19
- end
20
- end
21
-
22
23
  unless defined?(Diff)
23
24
  Diff = Invoca::Utils::Diff
24
25
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Invoca
4
+ module Utils
5
+ class << self
6
+ # Yields and rescues any exceptions given in `exception_classes`, retrying the given number of times.
7
+ # The final retry does not rescue any exceptions.
8
+ # The try number (0..retries) is yielded as a block param.
9
+ #
10
+ # @param [Class or Array(Class)] exception_classes - exception()s) to rescue
11
+ # @param [Integer] retries: - 1+ count of retries (1 retry = up to 2 tries total)
12
+ # @param [Proc] before_retry - optional proc which is called before each retry, with the exception passed as a block param
13
+ # @return the value from yield
14
+ def retry_on_exception(exception_classes, retries: 1, before_retry: nil)
15
+ retries.times do |attempt_number|
16
+ return yield(attempt_number)
17
+ rescue *Array(exception_classes) => ex
18
+ before_retry&.call(ex)
19
+ end
20
+
21
+ yield(retries) # no rescue for this last try, so any exceptions will raise out
22
+ end
23
+ end
24
+ end
25
+ end
@@ -21,6 +21,7 @@ module Invoca
21
21
  REPLACE_CHARACTER = '~'
22
22
 
23
23
  class << self
24
+ # normalizes a string to UTF-8
24
25
  def normalize_string(orig_string,
25
26
  normalize_utf16: true,
26
27
  normalize_cp1252: true,
@@ -43,6 +44,22 @@ module Invoca
43
44
  replace_unicode_beyond_ffff: replace_unicode_beyond_ffff)
44
45
  end
45
46
 
47
+ # Walks a JSON doc of hashes, arrays, and values and normalizes all strings found to UTF-8
48
+ def normalize_all_strings(value, **options)
49
+ case value
50
+ when Hash
51
+ value.each_with_object({}) do |(k, v), result|
52
+ result[normalize_all_strings(k, **options)] = normalize_all_strings(v, **options)
53
+ end
54
+ when Array
55
+ value.map { |v| normalize_all_strings(v, **options) }
56
+ when String
57
+ normalize_string(value, **options)
58
+ else
59
+ value
60
+ end
61
+ end
62
+
46
63
  private
47
64
 
48
65
  def normalize_string_from_utf8(string,
@@ -54,13 +71,11 @@ module Invoca
54
71
  found_utf_16 = normalize_utf_16(string, normalize_cp1252: normalize_cp1252) if normalize_utf16
55
72
  if found_utf_16
56
73
  string.encode!('UTF-8')
57
- else
58
- unless string.valid_encoding?
59
- if normalize_cp1252
60
- cp1252_to_utf_8(string)
61
- else
62
- raise ArgumentError, 'Could not normalize to utf8 due to invalid characters (probably CP1252)'
63
- end
74
+ elsif !string.valid_encoding?
75
+ if normalize_cp1252
76
+ cp1252_to_utf_8(string)
77
+ else
78
+ raise ArgumentError, 'Could not normalize to utf8 due to invalid characters (probably CP1252)'
64
79
  end
65
80
  end
66
81
  normalize_newlines(string) if normalize_newlines
@@ -2,7 +2,6 @@
2
2
 
3
3
  # Invoca ::Hash extensions
4
4
  class Hash
5
-
6
5
  def select_hash(&block)
7
6
  res = {}
8
7
  each { |k, v| res[k] = v if (block.arity == 1 ? yield(v) : yield(k, v)) } # rubocop:disable Style/ParenthesesAroundCondition
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Invoca
4
4
  module Utils
5
- VERSION = "0.3.0"
5
+ VERSION = "0.4.0"
6
6
  end
7
7
  end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../test_helper'
4
+
5
+ class ExceptionsTest < Minitest::Test
6
+ context "exceptions" do
7
+ context ".retry_on_exception" do
8
+ should "default retries: to 1" do
9
+ times = 0
10
+ tries = []
11
+ result = Invoca::Utils.retry_on_exception(ArgumentError) do |try|
12
+ tries << try
13
+ times += 1
14
+ end
15
+ assert_equal 1, result
16
+ assert_equal [0], tries
17
+ end
18
+
19
+ context "when never raising an exception" do
20
+ should "return result" do
21
+ times = 0
22
+ tries = []
23
+ result = Invoca::Utils.retry_on_exception(ArgumentError, retries: 2) do |try|
24
+ tries << try
25
+ times += 1
26
+ try == 0 and raise ArgumentError, '!!!'
27
+ times
28
+ end
29
+ assert_equal 2, result
30
+ assert_equal [0, 1], tries
31
+ end
32
+ end
33
+
34
+ context "when always raising an exception" do
35
+ should "retry and finally raise" do
36
+ tries = []
37
+ assert_raises(ArgumentError, /!!! 2/) do
38
+ Invoca::Utils.retry_on_exception(ArgumentError, retries: 1) do |try|
39
+ tries << try
40
+ raise ArgumentError, "!!! #{try + 1}"
41
+ end
42
+ end
43
+ assert_equal [0, 1], tries
44
+ end
45
+ end
46
+
47
+ context "when raising but then succeeding" do
48
+ should "retry and finally return result" do
49
+ times = 0
50
+ result = Invoca::Utils.retry_on_exception(ArgumentError, retries: 1) do
51
+ times += 1
52
+ if times == 1
53
+ raise ArgumentError, "!!! #{times}"
54
+ else
55
+ times
56
+ end
57
+ end
58
+ assert_equal 2, result
59
+ end
60
+ end
61
+
62
+ context "when raising different exceptions (array notation) but then succeeding" do
63
+ should "retry and finally return result" do
64
+ times = 0
65
+ tries = []
66
+ result = Invoca::Utils.retry_on_exception([ArgumentError, RuntimeError], retries: 2) do |try|
67
+ tries << try
68
+ times += 1
69
+ case times
70
+ when 1
71
+ raise ArgumentError, "!!! #{times}"
72
+ when 2
73
+ raise RuntimeError, "!!! #{times}"
74
+ else
75
+ times
76
+ end
77
+ end
78
+ assert_equal 3, result
79
+ assert_equal [0, 1, 2], tries
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -221,6 +221,29 @@ class GuaranteedUTF8StringTest < Minitest::Test
221
221
  assert_equal Encoding::UTF_8, encoded_string.encoding
222
222
  end
223
223
  end
224
+
225
+ context ".normalize_strings" do
226
+ should "walk json doc, replacing strings in: values, inside array elements, and hash keys and values" do
227
+ json_doc = {
228
+ '😹' => "\xE2\x9C\x93 laughing cat",
229
+ ['😹'] => ["\xE2", "\xf0\x9f\x98\xb9", { "newline" => "\r\n" }],
230
+ 'cp1252' => "\x91smart quotes\x92"
231
+ }
232
+
233
+ normalized_json = Invoca::Utils::GuaranteedUTF8String.normalize_all_strings(json_doc,
234
+ normalize_utf16: true,
235
+ normalize_cp1252: true,
236
+ normalize_newlines: true,
237
+ remove_utf8_bom: true,
238
+ replace_unicode_beyond_ffff: true)
239
+
240
+ assert_equal({
241
+ '~' => "✓ laughing cat",
242
+ ['~'] => ["â", "~", { "newline" => "\n" }],
243
+ 'cp1252' => "‘smart quotes’"
244
+ }, normalized_json)
245
+ end
246
+ end
224
247
  end
225
248
 
226
249
  context 'constructor' do
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: invoca-utils
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Invoca development
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-29 00:00:00.000000000 Z
11
+ date: 2020-06-09 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: A public collection of helpers used in multiple projects
13
+ description:
14
14
  email:
15
15
  - development@invoca.com
16
16
  executables: []
@@ -33,6 +33,7 @@ files:
33
33
  - lib/invoca/utils/array.rb
34
34
  - lib/invoca/utils/diff.rb
35
35
  - lib/invoca/utils/enumerable.rb
36
+ - lib/invoca/utils/exceptions.rb
36
37
  - lib/invoca/utils/guaranteed_utf8_string.rb
37
38
  - lib/invoca/utils/hash.rb
38
39
  - lib/invoca/utils/hash_with_indifferent_access.rb
@@ -48,6 +49,7 @@ files:
48
49
  - test/test_helper.rb
49
50
  - test/unit/array_test.rb
50
51
  - test/unit/enumerable_test.rb
52
+ - test/unit/exceptions_test.rb
51
53
  - test/unit/guaranteed_utf8_string_test.rb
52
54
  - test/unit/hash_test.rb
53
55
  - test/unit/hash_with_indifferent_access_test.rb
@@ -86,6 +88,7 @@ test_files:
86
88
  - test/test_helper.rb
87
89
  - test/unit/array_test.rb
88
90
  - test/unit/enumerable_test.rb
91
+ - test/unit/exceptions_test.rb
89
92
  - test/unit/guaranteed_utf8_string_test.rb
90
93
  - test/unit/hash_test.rb
91
94
  - test/unit/hash_with_indifferent_access_test.rb