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 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