trick_bag 0.30.0 → 0.31.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|