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 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(hash, keys)
9
- keys.reject { |key| hash.keys.include?(key) }
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(hash, keys)
15
- missing_keys = missing_hash_entries(hash, keys)
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
+
@@ -1,3 +1,3 @@
1
1
  module TrickBag
2
- VERSION = "0.30.0"
2
+ VERSION = "0.31.0"
3
3
  end
@@ -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
- it 'should return a correct list of missing keys' do
12
- h = { a: 1, c: 1, e: 1}
13
- keys_to_test = [:e, :d, :c, :b, :a]
14
- expect(missing_hash_entries(h, keys_to_test)).to eq([:d, :b])
15
- end
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
- it 'should return an empty array for no missing keys' do
19
- h = { a: 1, c: 1, e: 1}
20
- keys_to_test = [:e, :c, :a]
21
- expect(missing_hash_entries(h, keys_to_test)).to eq([])
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
- it 'should return a correct string listing missing keys' do
26
- h = { a: 1, c: 1, e: 1}
27
- keys_to_test = [:e, :d, :c, :b, :a]
28
- expect(missing_hash_entries_as_string(h, keys_to_test)).to eq('d, b')
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
- it 'should return nil instead of a string for no missing keys' do
33
- h = { a: 1, c: 1, e: 1}
34
- keys_to_test = [:e, :c, :a]
35
- expect(missing_hash_entries_as_string(h, keys_to_test)).to be_nil
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.30.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-04 00:00:00.000000000 Z
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