trick_bag 0.30.0 → 0.31.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.
- data/RELEASE_NOTES.md +8 -0
- data/lib/trick_bag/enumerables/endless_last_enumerable.rb +60 -0
- data/lib/trick_bag/formatters/formatters.rb +54 -0
- data/lib/trick_bag/validations/hash_validations.rb +18 -4
- data/lib/trick_bag/version.rb +1 -1
- data/spec/trick_bag/enumerables/endless_last_enumerable_spec.rb +51 -0
- data/spec/trick_bag/formatters/formatters_spec.rb +61 -0
- data/spec/trick_bag/validations/hashes_validations_spec.rb +47 -17
- metadata +8 -2
data/RELEASE_NOTES.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## v0.31.0
|
|
2
|
+
|
|
3
|
+
* Added EndlessLastEnumerable.
|
|
4
|
+
* Added Formatter module with duration_to_s and end_with_nl.
|
|
5
|
+
* Deleted IntegerDispenser. It had little that [].cycle.to_enum couldn't offer.
|
|
6
|
+
* In HashValidations: Add raise_on_missing_keys, permit passing either array or list.
|
|
7
|
+
|
|
8
|
+
|
|
1
9
|
## v0.30.0
|
|
2
10
|
|
|
3
11
|
* Initial public version.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module TrickBag
|
|
2
|
+
module Enumerables
|
|
3
|
+
|
|
4
|
+
# Takes an array as input. On successive calls to next, it returns the next
|
|
5
|
+
# element in the array until the array has been exhausted, and then returns
|
|
6
|
+
# the last element every time it's called.
|
|
7
|
+
#
|
|
8
|
+
# You can use Ruby's array addition and multiplication features
|
|
9
|
+
# to provide rich functionality, e.g.:
|
|
10
|
+
#
|
|
11
|
+
# array = [1] + [15]*3 + [60]*15 + [300]
|
|
12
|
+
#
|
|
13
|
+
# Values should only be nonzero positive integers.
|
|
14
|
+
#
|
|
15
|
+
# Why would this ever be useful? It was created for the benefit of a long
|
|
16
|
+
# running program, to provide time intervals for checking and reporting.
|
|
17
|
+
# It was helpful to report frequently at the beginning of the run, to give
|
|
18
|
+
# the user an opportunity to more easily verify correct behavior. Since
|
|
19
|
+
# the operations performed were potentially time consuming, we did not
|
|
20
|
+
# want to perform them frequently after the beginning of the run.
|
|
21
|
+
# For example, the array provided might have been [1] + [5] * 10 + [10] * 10 + [30].
|
|
22
|
+
class EndlessLastEnumerable
|
|
23
|
+
|
|
24
|
+
include Enumerable
|
|
25
|
+
|
|
26
|
+
attr_reader :array
|
|
27
|
+
|
|
28
|
+
def initialize(array_or_number)
|
|
29
|
+
@array = case array_or_number
|
|
30
|
+
when Array
|
|
31
|
+
array_or_number
|
|
32
|
+
when Numeric
|
|
33
|
+
[array_or_number]
|
|
34
|
+
else
|
|
35
|
+
raise RuntimeError.new("Unsupported data type (#{array_or_number.class}.")
|
|
36
|
+
end
|
|
37
|
+
@pos = 0
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def each
|
|
42
|
+
return to_enum unless block_given?
|
|
43
|
+
loop do
|
|
44
|
+
if @pos >= @array.size
|
|
45
|
+
value = @array.last
|
|
46
|
+
else
|
|
47
|
+
value = @array[@pos]
|
|
48
|
+
@pos += 1
|
|
49
|
+
end
|
|
50
|
+
yield(value)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def ==(other) # mostly for testing
|
|
56
|
+
other.is_a?(self.class) && other.array == array
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module TrickBag
|
|
2
|
+
module Formatters
|
|
3
|
+
|
|
4
|
+
module_function
|
|
5
|
+
|
|
6
|
+
def duration_to_s(seconds)
|
|
7
|
+
|
|
8
|
+
seconds_in_minute = 60
|
|
9
|
+
seconds_in_hour = 60 * seconds_in_minute
|
|
10
|
+
seconds_in_day = 24 *seconds_in_hour
|
|
11
|
+
|
|
12
|
+
seconds = seconds.to_i
|
|
13
|
+
str = ''
|
|
14
|
+
|
|
15
|
+
if seconds < 0
|
|
16
|
+
str << '-'
|
|
17
|
+
seconds = -seconds
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
fractional_second = seconds - Integer(seconds)
|
|
21
|
+
seconds = Integer(seconds)
|
|
22
|
+
|
|
23
|
+
days = seconds / seconds_in_day
|
|
24
|
+
print_days = days > 0
|
|
25
|
+
seconds %= seconds_in_day
|
|
26
|
+
|
|
27
|
+
hours = seconds / seconds_in_hour
|
|
28
|
+
print_hours = hours > 0 || days > 0
|
|
29
|
+
seconds %= seconds_in_hour
|
|
30
|
+
|
|
31
|
+
minutes = seconds / seconds_in_minute
|
|
32
|
+
print_minutes = minutes > 0 || hours > 0 || days > 0
|
|
33
|
+
seconds %= seconds_in_minute
|
|
34
|
+
|
|
35
|
+
str << "#{days} d, " if print_days
|
|
36
|
+
str << "#{hours} h, " if print_hours
|
|
37
|
+
str << "#{minutes} m, " if print_minutes
|
|
38
|
+
str << "#{seconds + fractional_second} s"
|
|
39
|
+
|
|
40
|
+
str
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# Convert to string if not already a string.
|
|
45
|
+
# Append new line to string if the string is not empty and does not already end with one.
|
|
46
|
+
# This is to disable the Diffy warning message "No newline at end of file"
|
|
47
|
+
def end_with_nl(object)
|
|
48
|
+
string = object.to_s
|
|
49
|
+
needs_modifying = string && string.size > 0 && string[-1] != "\n"
|
|
50
|
+
needs_modifying ? "#{string}\n" : string
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
@@ -5,17 +5,31 @@ module HashValidations
|
|
|
5
5
|
|
|
6
6
|
# Looks to see which keys, if any, are missing from the hash.
|
|
7
7
|
# @return an array of missing keys (empty if none)
|
|
8
|
-
def missing_hash_entries(
|
|
9
|
-
|
|
8
|
+
def missing_hash_entries(the_hash, *keys)
|
|
9
|
+
# Support passing either an Array or multiple args:
|
|
10
|
+
if keys.size == 1 && keys.first.is_a?(Array)
|
|
11
|
+
keys = keys.first
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
keys.reject { |key| the_hash.keys.include?(key) }
|
|
10
15
|
end
|
|
11
16
|
|
|
12
17
|
# Looks to see which keys, if any, are missing from the hash.
|
|
13
18
|
# @return nil if none missing, else comma separated string of missing keys.
|
|
14
|
-
def missing_hash_entries_as_string(
|
|
15
|
-
missing_keys = missing_hash_entries(
|
|
19
|
+
def missing_hash_entries_as_string(the_hash, *keys)
|
|
20
|
+
missing_keys = missing_hash_entries(the_hash, *keys)
|
|
16
21
|
missing_keys.empty? ? nil : missing_keys.join(', ')
|
|
17
22
|
end
|
|
18
23
|
|
|
24
|
+
# Checks to see that all passed keys are present in the hash.
|
|
25
|
+
# If not, an exception is raised, with a message string listing the missing keys.
|
|
26
|
+
def raise_on_missing_keys(the_hash, *keys)
|
|
27
|
+
missing_entries_string = missing_hash_entries_as_string(the_hash, keys)
|
|
28
|
+
if missing_entries_string
|
|
29
|
+
raise "The following required options were not provided: #{missing_entries_string}"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
19
32
|
end
|
|
20
33
|
end
|
|
21
34
|
end
|
|
35
|
+
|
data/lib/trick_bag/version.rb
CHANGED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require_relative '../../spec_helper'
|
|
2
|
+
|
|
3
|
+
require 'trick_bag/enumerables/endless_last_enumerable'
|
|
4
|
+
|
|
5
|
+
module TrickBag::Enumerables
|
|
6
|
+
|
|
7
|
+
describe EndlessLastEnumerable do
|
|
8
|
+
|
|
9
|
+
it "should instantiate with an array" do
|
|
10
|
+
expect(->{ EndlessLastEnumerable.new([1]) }).not_to raise_error
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should return the 3rd element on the 3rd call to next" do
|
|
14
|
+
array = (0..10).to_a
|
|
15
|
+
e = EndlessLastEnumerable.new(array).each
|
|
16
|
+
2.times { e.next }
|
|
17
|
+
expect(e.next).to eq(2)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
it "should return the last value in the array when the iteration number >= the array size" do
|
|
22
|
+
array = (0..10).to_a
|
|
23
|
+
e = EndlessLastEnumerable.new(array).each
|
|
24
|
+
10.times { e.next }
|
|
25
|
+
2.times { expect(e.next).to eq(10) }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
it "should return the original array and then repeat the last" do
|
|
30
|
+
array = (0..7).to_a
|
|
31
|
+
e = EndlessLastEnumerable.new(array).each
|
|
32
|
+
expect(e.take(8)).to eq(array)
|
|
33
|
+
expect(e.take(12)).to eq([7] * 12)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "should return == for 2 instances created with the same array" do
|
|
37
|
+
array = (0..10).to_a
|
|
38
|
+
e1 = EndlessLastEnumerable.new(array)
|
|
39
|
+
e2 = EndlessLastEnumerable.new(array)
|
|
40
|
+
expect(e1).to eq(e2)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
it "should return != for 2 instances created with arrays that are not equal" do
|
|
45
|
+
e1 = EndlessLastEnumerable.new([1])
|
|
46
|
+
e2 = EndlessLastEnumerable.new([2, 1])
|
|
47
|
+
expect(e1).not_to eq(e2)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require_relative '../../spec_helper'
|
|
2
|
+
|
|
3
|
+
require 'trick_bag/formatters/formatters'
|
|
4
|
+
|
|
5
|
+
module TrickBag
|
|
6
|
+
|
|
7
|
+
describe Formatters do
|
|
8
|
+
|
|
9
|
+
context ".duration_to_s" do
|
|
10
|
+
|
|
11
|
+
specify "it will not permit a non-number" do
|
|
12
|
+
expect(->() { Formatters.duration_to_s([])}).to raise_error
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
expect_output_for_input = ->(expected_output, input) do
|
|
16
|
+
description = "it returns '#{expected_output}' for an input of #{input}"
|
|
17
|
+
specify description do
|
|
18
|
+
expect(Formatters.duration_to_s(input)).to eq(expected_output)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Positive numbers
|
|
23
|
+
expect_output_for_input.('1 s', 1)
|
|
24
|
+
expect_output_for_input.('1 m, 0 s', 60)
|
|
25
|
+
expect_output_for_input.('3 m, 37 s', 3 * 60 + 37)
|
|
26
|
+
expect_output_for_input.('1 h, 0 m, 0 s', 60 * 60)
|
|
27
|
+
expect_output_for_input.('1 d, 0 h, 0 m, 0 s', 24 * 60 * 60)
|
|
28
|
+
|
|
29
|
+
# Negative numbers
|
|
30
|
+
expect_output_for_input.('-1 s', -1)
|
|
31
|
+
expect_output_for_input.('-1 m, 0 s', -60)
|
|
32
|
+
expect_output_for_input.('-3 m, 37 s', -(3 * 60 + 37))
|
|
33
|
+
expect_output_for_input.('-1 h, 0 m, 0 s', -60 * 60)
|
|
34
|
+
expect_output_for_input.('-1 d, 0 h, 0 m, 0 s', -24 * 60 * 60)
|
|
35
|
+
|
|
36
|
+
# Zero
|
|
37
|
+
expect_output_for_input.('0 s', 0)
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
context ".end_with_nl" do
|
|
43
|
+
|
|
44
|
+
specify "it returns an empty string for an empty string" do
|
|
45
|
+
expect(Formatters.end_with_nl('')).to eq('')
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
specify "it leaves a single new line unchanged" do
|
|
49
|
+
expect(Formatters.end_with_nl("\n")).to eq("\n")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
specify "it returns an empty string for nil because nil.to_s == ''" do
|
|
53
|
+
expect(Formatters.end_with_nl(nil)).to eq('')
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
specify "it converts a number and then adds a new line" do
|
|
57
|
+
expect(Formatters.end_with_nl(3)).to eq("3\n")
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -8,32 +8,62 @@ module Validations
|
|
|
8
8
|
|
|
9
9
|
include HashValidations
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
context '.missing_hash_entries' do
|
|
12
|
+
|
|
13
|
+
it 'should return a correct list of missing keys' do
|
|
14
|
+
h = { a: 1, c: 1, e: 1}
|
|
15
|
+
keys_to_test = [:e, :d, :c, :b, :a]
|
|
16
|
+
expect(missing_hash_entries(h, keys_to_test)).to eq([:d, :b])
|
|
17
|
+
end
|
|
16
18
|
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
it 'should return an empty array for no missing keys' do
|
|
21
|
+
h = { a: 1, c: 1, e: 1}
|
|
22
|
+
keys_to_test = [:e, :c, :a]
|
|
23
|
+
expect(missing_hash_entries(h, keys_to_test)).to eq([])
|
|
24
|
+
end
|
|
22
25
|
end
|
|
23
26
|
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
context '.missing_hash_entries_as_string' do
|
|
29
|
+
|
|
30
|
+
it 'should return a correct string listing missing keys' do
|
|
31
|
+
h = { a: 1, c: 1, e: 1}
|
|
32
|
+
keys_to_test = [:e, :d, :c, :b, :a]
|
|
33
|
+
expect(missing_hash_entries_as_string(h, keys_to_test)).to eq('d, b')
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
it 'should return nil instead of a string for no missing keys' do
|
|
38
|
+
h = { a: 1, c: 1, e: 1}
|
|
39
|
+
keys_to_test = [:e, :c, :a]
|
|
40
|
+
expect(missing_hash_entries_as_string(h, keys_to_test)).to be_nil
|
|
41
|
+
end
|
|
29
42
|
end
|
|
30
43
|
|
|
31
44
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
45
|
+
context '.raise_on_missing_keys'do
|
|
46
|
+
|
|
47
|
+
it 'should raise an exception whose message includes the missing keys' do
|
|
48
|
+
my_hash = {}
|
|
49
|
+
missing_keys = [:foo, :bar]
|
|
50
|
+
begin
|
|
51
|
+
raise_on_missing_keys(my_hash, missing_keys)
|
|
52
|
+
fail "An exception should have been raised."
|
|
53
|
+
rescue => e
|
|
54
|
+
message = e.to_s
|
|
55
|
+
missing_keys.each do |key|
|
|
56
|
+
expect(message).to include(key.to_s)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it 'should not raise an exception when all keys are present' do
|
|
62
|
+
my_hash = { foo: 1, bar: 2, baz: 3}
|
|
63
|
+
expect(->() { raise_on_missing_keys(my_hash, :foo, :baz) }).not_to raise_error
|
|
64
|
+
end
|
|
36
65
|
end
|
|
37
66
|
end
|
|
38
67
|
end
|
|
39
68
|
end
|
|
69
|
+
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: trick_bag
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.31.0
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2014-03-
|
|
12
|
+
date: 2014-03-05 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: vrsn-ie-dnsruby
|
|
@@ -125,7 +125,9 @@ files:
|
|
|
125
125
|
- lib/trick_bag/collections/linked_list.rb
|
|
126
126
|
- lib/trick_bag/enumerables/buffered_enumerable.rb
|
|
127
127
|
- lib/trick_bag/enumerables/compound_enumerable.rb
|
|
128
|
+
- lib/trick_bag/enumerables/endless_last_enumerable.rb
|
|
128
129
|
- lib/trick_bag/enumerables/filtered_enumerable.rb
|
|
130
|
+
- lib/trick_bag/formatters/formatters.rb
|
|
129
131
|
- lib/trick_bag/io/temp_files.rb
|
|
130
132
|
- lib/trick_bag/io/text_mode_status_updater.rb
|
|
131
133
|
- lib/trick_bag/meta/classes.rb
|
|
@@ -140,7 +142,9 @@ files:
|
|
|
140
142
|
- spec/trick_bag/collections/linked_list_spec.rb
|
|
141
143
|
- spec/trick_bag/enumerables/buffered_enumerable_spec.rb
|
|
142
144
|
- spec/trick_bag/enumerables/compound_enumerable_spec.rb
|
|
145
|
+
- spec/trick_bag/enumerables/endless_last_enumerable_spec.rb
|
|
143
146
|
- spec/trick_bag/enumerables/filtered_enumerable_spec.rb
|
|
147
|
+
- spec/trick_bag/formatters/formatters_spec.rb
|
|
144
148
|
- spec/trick_bag/io/temp_files_spec.rb
|
|
145
149
|
- spec/trick_bag/io/text_mode_status_updater_spec.rb
|
|
146
150
|
- spec/trick_bag/meta/classes_spec.rb
|
|
@@ -181,7 +185,9 @@ test_files:
|
|
|
181
185
|
- spec/trick_bag/collections/linked_list_spec.rb
|
|
182
186
|
- spec/trick_bag/enumerables/buffered_enumerable_spec.rb
|
|
183
187
|
- spec/trick_bag/enumerables/compound_enumerable_spec.rb
|
|
188
|
+
- spec/trick_bag/enumerables/endless_last_enumerable_spec.rb
|
|
184
189
|
- spec/trick_bag/enumerables/filtered_enumerable_spec.rb
|
|
190
|
+
- spec/trick_bag/formatters/formatters_spec.rb
|
|
185
191
|
- spec/trick_bag/io/temp_files_spec.rb
|
|
186
192
|
- spec/trick_bag/io/text_mode_status_updater_spec.rb
|
|
187
193
|
- spec/trick_bag/meta/classes_spec.rb
|