more_ruby 0.2.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5b1771efb7dc83fea53e24b2d7b5a2f67fa7d1e2cdca9dec76ef81ad09817c30
4
+ data.tar.gz: 46a7e965a7449f3f6e0258f355e414cc2f537ad8f2c2284f06a63fddf515e26b
5
+ SHA512:
6
+ metadata.gz: 6a8b12b7cf3c75568bfbce46433e6b07e315524ffb34d2b37bdf2f3cae73c0919e2f075f9425a88cd55638caa76e85928c04dcb02a42f1503a173dafaba15012
7
+ data.tar.gz: 3ad555c95b8f5c8512a6b24522dea8b434539584ecb237c66e56ad9154f26863a168fc16b55df38275cace7ac8e248ca9648e7587c776599ed6f0b0c2cc6aea8
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2016 Richard Morrisby
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,43 @@
1
+ A very simple gem that adds some methods to some Ruby standard classes, e.g. <array>.include_any?, <array>.delete_random, etc.
2
+
3
+ Simply require the gem ( require "more_ruby" ) and the additional methods will be available.
4
+
5
+ # New instance methods #
6
+
7
+ ## Array
8
+ :all_instance_of?, :all_kind_of?, :av, :delete_random, :include_any?, :insert_flat, :mean, :modulo_fetch, :peach, :random, :random_index, :random_insert, :random_move, :stringify_all_values_deep, :sum, :wrap_fetch
9
+
10
+ ## Fixnum
11
+ :digit_count, :format_with_thousands_delimiter, :num_to_letter, :signif
12
+
13
+ ## Float
14
+ :format_with_thousands_delimiter, :signif
15
+
16
+ ## Hash
17
+ :all_keys, :all_values, :delete_random, :peach, :random_key, :random_pair, :random_value, :remove_empty_fields, :sort_deep, :stringify_all_values_deep, :strip_hash_of_keys, :to_a_deep, :to_xml
18
+
19
+ ## Integer
20
+ :digit_count, :format_with_thousands_delimiter, :signif
21
+
22
+ ## NilClass
23
+ :empty?
24
+
25
+ ## Numeric
26
+ :format_with_thousands_delimiter
27
+
28
+ ## String
29
+ :append, :camelcase, :camelcase_to_snakecase, :capitalize_all, :capitalize_first_letter_only, :escape, :escape_whitespace, :extract_values_from_xml_string, :formatted_number, :index_of_last_capital, :invert_case, :is_hex?, :is_integer?, :join, :pascalcase, :prefix_lines, :random_case, :snakecase, :snakecase_and_downcase, :to_bool, :unindent
30
+
31
+ ## Time
32
+ :is_after?, :is_before?, :is_within?, :remove_subseconds
33
+
34
+ # New singleton methods #
35
+
36
+ ## FalseClass
37
+ :maybe?, :random
38
+
39
+ ## File
40
+ :basename_no_ext
41
+
42
+ ## TrueClass
43
+ :maybe?, :random
@@ -0,0 +1,15 @@
1
+
2
+ require_relative 'more_ruby/array.rb'
3
+ require_relative 'more_ruby/enumerable.rb'
4
+ require_relative 'more_ruby/falseclass.rb'
5
+ require_relative 'more_ruby/file.rb'
6
+ require_relative 'more_ruby/fixnum.rb'
7
+ require_relative 'more_ruby/float.rb'
8
+ require_relative 'more_ruby/hash.rb'
9
+ require_relative 'more_ruby/integer.rb'
10
+ require_relative 'more_ruby/nilclass.rb'
11
+ require_relative 'more_ruby/numeric.rb'
12
+ require_relative 'more_ruby/string.rb'
13
+ require_relative 'more_ruby/time.rb'
14
+ require_relative 'more_ruby/trueclass.rb'
15
+
@@ -0,0 +1,119 @@
1
+
2
+ class Array
3
+ # Does the array contain any of the supplied items?
4
+ def include_any?(*items)
5
+ items.each do |i|
6
+ return true if self.include? i
7
+ end
8
+ false
9
+ end
10
+
11
+ # Return a random item from the array (by index)
12
+ def random
13
+ self[rand(size)]
14
+ end
15
+
16
+ # Deletes at a random index from the array, and returns the deleted item
17
+ def delete_random
18
+ index = rand(size)
19
+ item = self[index]
20
+ delete_at(index)
21
+ item
22
+ end
23
+
24
+ def random_index
25
+ rand(size)
26
+ end
27
+
28
+ # Insert the supplied element to a random position within the array
29
+ def random_insert(element)
30
+ insert(rand(size), element)
31
+ end
32
+
33
+ # Move a random element to a random position in the array
34
+ def random_move(times = 1)
35
+ times.times do
36
+ element = delete_random
37
+ random_insert(element)
38
+ end
39
+ end
40
+
41
+ # Returns the mean / average of the Numeric array. Returns a float. All entries must be Numeric.
42
+ def mean
43
+ each {|item| raise TypeError, "Cannot determine the mean of an array that contains non-Numeric objects." unless item.kind_of?(Numeric)}
44
+ inject{ |sum, item| sum + item }.to_f / size
45
+ end
46
+ alias :av :mean
47
+
48
+ # Returns the summation of the contents of the array
49
+ # Ignores nils; raises if the array contains a non-Numeric non-nil
50
+ def sum
51
+ raise TypeError, "Array contained non-numeric non-nil elements; cannot sum contents." unless compact.all_kind_of? Numeric
52
+ compact.inject(0) do |sum, item|
53
+ sum += item
54
+ end
55
+ end
56
+
57
+ # Will insert each member of the supplied array into self, such that self does not contain a new sub-array
58
+ # Insertion behaviour is more like += than << , e.g. [1, 2, 3].insert_flat(0, [4, 5]) => [4, 5, 1, 2, 3]
59
+ # Does not flatten self, so any preexisting subarrays are preserved
60
+ def insert_flat(index, o)
61
+ case o
62
+ when Array
63
+ # A -ve insertion index inserts items AFTER the item at that index, which causes problems when inserting multiple times
64
+ # Use o.each when -ve ; o.reverse_each when +ve or zero
65
+ if index < 0
66
+ o.each do |item|
67
+ insert(index, item)
68
+ end
69
+ else
70
+ o.reverse_each do |item|
71
+ insert(index, item)
72
+ end
73
+ end
74
+ else
75
+ insert(index, o)
76
+ end
77
+ end
78
+
79
+ # A simple method to fetch the item at the index. If index > size, then it 'wraps' around and looks again
80
+ # E.g. [0, 1, 2].wrap_fetch(4) returns 1
81
+ # Operation is effectively fetch(index % size)
82
+ def wrap_fetch(index)
83
+ return nil if empty?
84
+ fetch(index % size)
85
+ end
86
+ alias :modulo_fetch :wrap_fetch
87
+
88
+ # Returns true if all elements of self are kind_of?(klass)
89
+ def all_kind_of?(klass)
90
+ all? {|item| item.kind_of?(klass)}
91
+ end
92
+
93
+ # Returns true if all elements of self are instance_of?(klass)
94
+ def all_instance_of?(klass)
95
+ all? {|item| item.instance_of?(klass)}
96
+ end
97
+
98
+ # A prettier way of printing an array
99
+ # Want to p each row, but have each p appear on a new line in STDOUT
100
+ def peach
101
+ self.each { |z| p z }
102
+ end
103
+
104
+ # Method to convert all values to strings, for all layers within the array
105
+ def stringify_all_values_deep
106
+ for i in 0 ... size do
107
+ v = self[i]
108
+ case v
109
+ when Array, Hash
110
+ v = v.stringify_all_values_deep
111
+ else
112
+ v = v.to_s
113
+ end
114
+ self[i] = v
115
+ end
116
+ self
117
+ end
118
+
119
+ end
@@ -0,0 +1,11 @@
1
+
2
+ module Enumerable
3
+ def group_by
4
+ result = {}
5
+ self.each do |value|
6
+ key = yield(value)
7
+ (result[key] ||= []) << value
8
+ end
9
+ result
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ class FalseClass
2
+
3
+ # Yields true 50% of the time, otherwise yields false
4
+ def self.random
5
+ rand(2) % 2 == 0
6
+ end
7
+
8
+ def self.maybe?
9
+ random
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+
2
+ class File
3
+ # Returns the file's basename without its extension
4
+ def self.basename_no_ext f
5
+ File.basename(f, File.extname(f))
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+
2
+ class Fixnum
3
+
4
+ # Converts the number (1 <= x <= 26) to a letter
5
+ # 1 => A, 9 => I, 0 has no corresponding letter
6
+ def num_to_letter
7
+ raise "Do not call num_to_letter with a number that is not between 1 and 26" unless self >= 1 && self <= 26
8
+ (self.to_i + 64).chr
9
+ end
10
+ end
@@ -0,0 +1,53 @@
1
+
2
+
3
+ class Float
4
+
5
+ # Two cases : self.abs >= 1, and self.abs < 1
6
+ # If >= 1, we can use .round(), adjusting for the number of digits before the decimal point
7
+ # If < 1, .round() will not ignore leading zeroes, so we have to use another means
8
+ # There is another complication in that 0.00000766.to_s returns 7.66e-06 , not 0.00000766 as we would prefer here
9
+ def signif(num_digits)
10
+ raise TypeError, "Must call #{__method__} with an Integer" unless num_digits.kind_of?(Integer)
11
+ raise ArgumentError, "Must call #{__method__} with a positive Integer" if num_digits < 0 # 0 is a special case, but allowed
12
+ # Special cases
13
+ return 0.0 if num_digits == 0
14
+ return self if self == 0.0
15
+
16
+ negative = self < 0 # remember its sign for later
17
+
18
+ # Need to check to see if the numebr is small enough that to_s will put it into scientific notation
19
+ if self.to_s =~ /^(\d)\.(\d*)e-(\d+)$/
20
+ places = 1 + $2.size + $3.to_i
21
+ s = "%.#{places}f" % self # should print out 7.66e-06 as 0.00000766
22
+ else
23
+ s = self.to_s
24
+ end
25
+ parts = s.split(".")
26
+ whole = parts[0].to_i.abs
27
+
28
+ # significant figures ignore leading zeroes, so we can only return early here if self.abs > 1
29
+ # 123.456.signif(4) should return 123.4; 123.456.signif(3) should return 123
30
+ if whole != 0 # equivalent to self.abs > 1
31
+ if num_digits <= whole.digit_count
32
+ return whole.signif(num_digits).to_f
33
+ else
34
+ return self.round(num_digits - whole.digit_count)
35
+ end
36
+ end
37
+
38
+ fraction_as_s = parts[1] # keep as string for now
39
+ return whole.signif(num_digits).to_f unless fraction_as_s # should not be possible, but check it anyway
40
+ return whole.signif(num_digits).to_f if fraction_as_s == "0"
41
+
42
+ relevant_fraction_digits = num_digits
43
+ fraction = "0.#{fraction_as_s}".to_f
44
+ fraction_as_s =~ /^([0]*)[1-9]/
45
+ leading_zeroes_count = $1.size
46
+ rounded_fraction = fraction.round(relevant_fraction_digits + leading_zeroes_count)
47
+ if negative
48
+ return -(rounded_fraction)
49
+ else
50
+ return rounded_fraction
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,202 @@
1
+
2
+ class Hash
3
+
4
+ def random_value
5
+ self.values.random
6
+ end
7
+
8
+ def random_key
9
+ self.keys.random
10
+ end
11
+
12
+ # Returns a hash of the key and value
13
+ def random_pair
14
+ key = random_key
15
+ {key => self[key]}
16
+ end
17
+
18
+ def delete_random
19
+ delete(self.random_key)
20
+ end
21
+
22
+ # Gathers all keys in the hash in a flat array, even if it's multi-level
23
+ # E.g. from {:a => :b, :c => {:d => :e}}, returns [:a, :c, :d]
24
+ def all_keys
25
+ list = []
26
+ self.each_pair do |k, v|
27
+ case k
28
+ when Hash
29
+ list += k.all_keys
30
+ when Array
31
+ if k[0].class == Hash # if the array contains hashes
32
+ k.each do |array_item|
33
+ list += array_item.all_keys
34
+ end
35
+ else
36
+ list << k
37
+ end
38
+ else
39
+ list << k
40
+ end # end case k
41
+
42
+ case v
43
+ when Hash
44
+ list += v.all_keys
45
+ when Array
46
+ if v[0].class == Hash # if the array contains hashes
47
+ v.each do |array_item|
48
+ list += array_item.all_keys
49
+ end
50
+ else
51
+ # do nothing
52
+ end
53
+ else
54
+ # do nothing
55
+ end # end case v
56
+ end
57
+ list
58
+ end
59
+
60
+ # Gathers all values in the hash in a flat array, even if it's multi-level
61
+ # E.g. from {:a => :b, :c => {:d => :e}}, returns [:b, :e]
62
+ def all_values
63
+ list = []
64
+ self.each_pair do |k, v|
65
+ case k
66
+ when Hash
67
+ list += k.all_values
68
+ when Array
69
+ if k[0].class == Hash # if the array contains hashes
70
+ k.each do |array_item|
71
+ list += array_item.all_values
72
+ end
73
+ else
74
+ # do nothing
75
+ end
76
+ else
77
+ # do nothing
78
+ end # end case k
79
+
80
+ case v
81
+ when Hash
82
+ list += v.all_values
83
+ when Array
84
+ if v[0].class == Hash # if the array contains hashes
85
+ v.each do |array_item|
86
+ list += array_item.all_values
87
+ end
88
+ else
89
+ list << v
90
+ end
91
+ else
92
+ list << v
93
+ end # end case v
94
+ end
95
+ list
96
+ end
97
+
98
+ # Method to convert all values to strings, for all layers within the hash
99
+ def stringify_all_values_deep
100
+ self.each_pair do |k, v|
101
+ case v
102
+ when Array, Hash
103
+ v = v.stringify_all_values_deep
104
+ else
105
+ self[k] = v.to_s
106
+ end
107
+ end
108
+ self
109
+ end
110
+
111
+ # A prettier way of printing a hash
112
+ # Want to p each pair, but have each p appear on a new line in STDOUT
113
+ def peach
114
+ self.each_pair { |k, v| puts "#{k.inspect} => #{v.inspect}" }
115
+ end
116
+
117
+ # Recursively deletes keys from the hash if the value of that field is nil or empty
118
+ def remove_empty_fields
119
+ self.each_pair do |k, v|
120
+ if self[k].class == Hash
121
+ self[k] = self[k].remove_empty_fields
122
+ else
123
+ self.delete(k) if v.to_s == ""
124
+ end
125
+ end
126
+ self
127
+ end
128
+
129
+ # Method to strip from the hash (and all sub-hashes) all keys matching the entries in the supplied array
130
+ # Entries in the array can be strings or other literals, or regexes
131
+ # Directly deletes from self; returns the modified self
132
+ def strip_hash_of_keys(array_of_keys_to_strip)
133
+ self.keys.each do |k|
134
+ strip = false
135
+ array_of_keys_to_strip.each do |i|
136
+ if i.class == Regexp
137
+ strip = true if k =~ i
138
+ else
139
+ strip = true if k == i
140
+ end
141
+ end
142
+
143
+ if strip
144
+ self.delete(k)
145
+ else
146
+ if self[k].class == Hash
147
+ self[k] = self[k].strip_hash_of_keys(array_of_keys_to_strip)
148
+ elsif self[k].class == Array
149
+ self[k].each do |h|
150
+ h = h.strip_hash_of_keys(array_of_keys_to_strip) if h.class == Hash
151
+ end
152
+ end
153
+ end
154
+ end
155
+ self
156
+ end
157
+
158
+ # Method to fully convert the hash into an array, including all sub-hashes
159
+ # to_a only converts the base level
160
+ def to_a_deep
161
+ self.keys.each do |k|
162
+ if self[k].class == Hash
163
+ self[k] = self[k].to_a_deep
164
+ end
165
+ end
166
+ self.to_a
167
+ end
168
+
169
+ # Sorts the hash by its keys. This way, if two versions of the hash (mhich are identical but their k-v pairs are in different order)
170
+ # are both sorted then converted to string (to_s) they will be identical.
171
+ # Assumes that all of the keys in the hash are symbol/string/numeric and are not Hash, Array, etc.
172
+ # Assumes that each key in the hash is unique
173
+ # Sorts deep, not shallow
174
+ # Returns a new hash; does not modify self
175
+ def sort_deep
176
+ new = {}
177
+ keys = self.keys.sort
178
+ keys.each do |main_key|
179
+ self.each_pair do |k, v|
180
+ next unless k == main_key
181
+ if v.class == Hash
182
+ new[k] = v.sort_deep
183
+ else
184
+ new[k] = v
185
+ end
186
+ end
187
+ end
188
+ new
189
+ end
190
+
191
+ def to_xml
192
+ map do |k, v|
193
+ if v.class == Hash
194
+ text = v.to_xml
195
+ else
196
+ text = v
197
+ end
198
+ "<%s>%s</%s>" % [k, text, k]
199
+ end.join
200
+ end
201
+
202
+ end
@@ -0,0 +1,20 @@
1
+ require 'bigdecimal'
2
+
3
+ class Integer
4
+
5
+ # Returns the number of digits in the number
6
+ def digit_count
7
+ self.to_s.size
8
+ end
9
+
10
+ # Code taken from https://www.ruby-forum.com/topic/187036 ; all credit for mechanism goes to Harry Kakueki
11
+ # Method is same as Float#signif below; dangerous to add to common parent Numeric?
12
+ def signif(num_digits)
13
+ raise TypeError, "Must call #{__method__} with an Integer" unless num_digits.kind_of?(Integer)
14
+ raise ArgumentError, "Must call #{__method__} with a positive Integer" if num_digits < 0 # 0 is a special case, but allowed
15
+ return 0.0 if num_digits == 0
16
+ return self if self.digit_count <= num_digits
17
+ m = (num_digits - 1) - Math.log10(self.abs).floor
18
+ BigDecimal.new(((self * 10 ** m).round * 10 ** (-1 * m)).to_s).to_s('F').gsub(/\.0*$/,"").to_i
19
+ end
20
+ end
@@ -0,0 +1,10 @@
1
+
2
+ class NilClass
3
+
4
+ # A simple routing method in case your empty array is actually nil
5
+ # If you're calling empty?, you care if there is data in there, not if the object is actually an array
6
+ # nil is obviously empty, so return true instead of NoMethodError
7
+ def empty?
8
+ true
9
+ end
10
+ end
@@ -0,0 +1,18 @@
1
+
2
+ class Numeric
3
+
4
+ # Returns a more print-friendly version of the number
5
+ # e.g. 1234567.8901 => 1,234,567.8901
6
+ # Returns a string
7
+ # Copied from http://stackoverflow.com/questions/6458990/how-to-format-a-number-1000-as-1-000
8
+ # Credit goes to user "loosecannon"
9
+ def format_with_thousands_delimiter(delimiter = ",")
10
+ parts = to_s.split(".")
11
+ if parts.size == 2
12
+ parts[0].reverse.gsub(/...(?=.)/, '\&' + delimiter).reverse + "." + parts[1]
13
+ else
14
+ to_s.reverse.gsub(/...(?=.)/, '\&' + delimiter).reverse
15
+ end
16
+ end
17
+
18
+ end
@@ -0,0 +1,172 @@
1
+
2
+ class String
3
+
4
+ # .capitalize will upcase the first letter and lowercase everything else; this method does only the upcase part
5
+ def capitalize_first_letter_only
6
+ return self if empty?
7
+ return self[0].upcase + self[1 .. -1] # self[1 .. -1] will return "" if self is only one character long
8
+ end
9
+
10
+ # Returns new string, does not modify in place
11
+ def escape
12
+ Regexp.escape(self)
13
+ end
14
+
15
+ # Returns a new string with each character's case randomised
16
+ def random_case
17
+ new = ""
18
+ self.each_char do |x|
19
+ new << ((rand(2) % 2 == 0) ? x.upcase : x.downcase)
20
+ end
21
+ new
22
+ end
23
+
24
+ def capitalize_all
25
+ downcase.scan(/[a-z0-9]+/).map { |z| z.capitalize }.join(' ')
26
+ end
27
+
28
+ def invert_case
29
+ s = ""
30
+ self.chars do |c|
31
+ if c =~ /[A-Z]/
32
+ s << c.downcase
33
+ elsif c =~ /[a-z]/
34
+ s << c.upcase
35
+ else
36
+ s << c
37
+ end
38
+ end
39
+ raise "invert_case failed!" unless s.size == self.size
40
+ s
41
+ end
42
+
43
+ # Prefixes each line with the supplied string
44
+ def prefix_lines(prefix)
45
+ gsub(/^/) { prefix }
46
+ end
47
+
48
+ # Remove leading whitespace from each line in the string, using the indentation of the first line as the guide
49
+ def unindent
50
+ leading_whitespace = self[/\A\s*/]
51
+ self.gsub(/^#{leading_whitespace}/, '')
52
+ end
53
+
54
+ # Returns the index of the last capital in the string (if one exists)
55
+ def index_of_last_capital
56
+ pos = 0
57
+ reverse_index = self.reverse.index /[A-Z]/
58
+ return nil if reverse_index == nil
59
+ self.size - reverse_index - 1
60
+ end
61
+
62
+ def snakecase
63
+ gsub(/[^a-zA-Z0-9]+/, '_')
64
+ end
65
+
66
+ def snakecase_and_downcase
67
+ downcase.snakecase
68
+ end
69
+
70
+ # Like camelcase but with the first letter also capitalised
71
+ # Pascalcase is C#'s case convention
72
+ def pascalcase
73
+ downcase.scan(/[a-z0-9]+/).map { |x| x.capitalize }.join
74
+ end
75
+
76
+ def camelcase
77
+ s = self.pascalcase
78
+ s[0].downcase + s[1 .. -1]
79
+ end
80
+
81
+ # Converts aStringInCamelCase to a_string_in_camel_case
82
+ def camelcase_to_snakecase
83
+ a = []
84
+
85
+ self =~ /(^[a-z]+)/
86
+ a << $1 if $1
87
+
88
+ m = self.scan /([A-Z]+[a-z0-9]*)/
89
+ m.flatten!
90
+ m.each do |fragment|
91
+ fragment =~ /([A-Z]+[a-z0-9]*)/
92
+ caps = $1
93
+ lower = $2
94
+ if caps.size > 1
95
+ s = "_#{caps.downcase}"
96
+ a << s
97
+ caps = "" # set to empty string so that the below caps.downcase still works
98
+ end
99
+ s = "_#{caps.downcase}#{lower}"
100
+ a << s unless s == "_"
101
+ end
102
+ a.join
103
+ end
104
+
105
+ def append(s)
106
+ self << s
107
+ end
108
+
109
+ def join(s = "")
110
+ append(s)
111
+ end
112
+
113
+ def to_bool
114
+ return true if self.downcase == "true"
115
+ return false if self.downcase == "false"
116
+ raise "String #{self} was neither 'true' nor 'false'. Cannot convert to boolean in this custom method."
117
+ end
118
+
119
+ # Does the string look like an integer?
120
+ # !! will convrt nil to false, and anythig else (e.g. 0) to true
121
+ def is_integer?
122
+ !!(self =~ /^[0-9]+$/)
123
+ end
124
+
125
+ # Does the string look like hex?
126
+ # !! will convrt nil to false, and anythig else (e.g. 0) to true
127
+ def is_hex?
128
+ !!(self =~ /^[0-9a-fA-F]+$/)
129
+ end
130
+
131
+ def formatted_number(separator = ",", count_limit = 3)
132
+ copy = self.dup
133
+ s = ""
134
+ count = 0
135
+ while copy.size > 0
136
+ if count == count_limit
137
+ s << separator
138
+ count = 0
139
+ else
140
+ count += 1
141
+ s << copy[-1]
142
+ copy.chop!
143
+ end
144
+ end
145
+ s.reverse
146
+ end
147
+
148
+ # Take the XML-string and remove from it anything that looks like an XML tag
149
+ def extract_values_from_xml_string
150
+ values = []
151
+ a = self.split("<").collect { |z| z.chomp } # need to remove whitespace where possible
152
+ # Now remove from the array any items that end in a > - these items look like fragments of tags
153
+ a.delete_if { |z| z =~ />$/ }
154
+
155
+ # a might now contain nils, "" and items like "foo>bar"
156
+ a.delete_if { |z| z == "" }
157
+ a.compact!
158
+ a.each { |z| values << z.split(">")[1] }
159
+
160
+ values
161
+ end
162
+
163
+ # Within the string, whitespace chars (\n, \r, \t) are replaced by their text equivalents, e.g. \n => \\n
164
+ # Does not modify self
165
+ def escape_whitespace
166
+ copy = self.dup
167
+ copy.gsub!("\n", "\\n")
168
+ copy.gsub!("\r", "\\r")
169
+ copy.gsub!("\t", "\\t")
170
+ copy
171
+ end
172
+ end
@@ -0,0 +1,31 @@
1
+
2
+ class Time
3
+
4
+ # Returns a new Time object with all subseconds set to zero
5
+ def remove_subseconds
6
+ ms = self.subsec
7
+ self.clone - ms
8
+ end
9
+
10
+ # Method to compare self against other_time, returning true if self is equal to or earlier/before other_time
11
+ # This comparison is made with some leeway, so that if self is actually after other_time, but by less than
12
+ # the leeway amount (in seconds), the method will return true
13
+ def is_before?(other_time, leeway = 5)
14
+ other_time += leeway
15
+ self <= other_time
16
+ end
17
+
18
+ # Method to compare self against other_time, returning true if self is equal to or later/after other_time
19
+ # This comparison is made with some leeway, so that if self is actually before other_time, but by less than
20
+ # the leeway amount (in seconds), the method will return true
21
+ def is_after?(other_time, leeway = 5)
22
+ other_time -= leeway
23
+ self >= other_time
24
+ end
25
+
26
+ # Method to compare self against other_time, returning true if it is close enough to self in either direction
27
+ # Leeway is in seconds
28
+ def is_within?(other_time, leeway = 5)
29
+ is_before?(other_time, leeway) && is_after?(other_time, leeway)
30
+ end
31
+ end
@@ -0,0 +1,12 @@
1
+
2
+ class TrueClass
3
+
4
+ # Yields true 50% of the time, otherwise yields false
5
+ def self.random
6
+ rand(2) % 2 == 0
7
+ end
8
+
9
+ def self.maybe?
10
+ random
11
+ end
12
+ end
@@ -0,0 +1,193 @@
1
+ require "test/unit"
2
+ require_relative "../lib/more_ruby"
3
+
4
+ class TestArray < Test::Unit::TestCase
5
+
6
+ def test_random
7
+ a = (1 .. 20).to_a
8
+ randoms = []
9
+ count = 20
10
+ count.times do
11
+ randoms << a.random
12
+ end
13
+
14
+ assert_equal(count, randoms.size)
15
+
16
+ randoms.compact!
17
+ assert_equal(count, randoms.size, ".random returned nils")
18
+
19
+ randoms.uniq!
20
+ assert_empty(randoms - a, ".random returned values not in the original array")
21
+
22
+ # Extremely unlikely to happen, but rand may roll in order for every call in this test
23
+ assert_not_equal(a, randoms, ".random did not return values in a random order")
24
+ end
25
+
26
+ def test_delete_random_size
27
+ orig_size = 20
28
+ a = (1 .. orig_size).to_a
29
+ count = 10
30
+ count.times do |i|
31
+ deleted = a.delete_random
32
+
33
+ assert_not_equal(orig_size, a.size, ".delete_random is not deleting from self")
34
+
35
+ assert_equal(orig_size - (i + 1), a.size, ".delete_random is deleting too many from self")
36
+
37
+ # TODO would be nice to test randomness, but that's pretty difficult
38
+ end
39
+ end
40
+
41
+ def test_delete_random_return
42
+ b = [3, 3, 3]
43
+ deleted = b.delete_random
44
+
45
+ assert_not_empty(b, ".delete_random is deleting by object, not by index")
46
+ assert_not_equal(b.uniq, b, ".delete_random is deleting by object, not by index")
47
+ assert_equal(deleted, b.random, ".delete_random is not returning the deleted item")
48
+ assert_not_nil(deleted, ".delete_random is not returning the deleted item")
49
+
50
+ end
51
+
52
+ def test_mean
53
+ a = (1 .. 6).to_a # mean is 3.5
54
+ expected = 3.5
55
+ mean = a.mean
56
+ assert_kind_of(Float, mean, ".mean did not return a Float")
57
+ assert_equal(mean, expected, ".mean is not returning the correct mean")
58
+ end
59
+
60
+ def test_av
61
+ a = (1 .. 6).to_a # mean is 3.5
62
+ expected = 3.5
63
+ mean = a.av
64
+ assert_kind_of(Float, mean, ".av did not return a Float")
65
+ assert_equal(mean, expected, ".av is not returning the correct mean")
66
+ end
67
+
68
+ def test_mean_mixed_numerics
69
+ a = [1, 2.0, -6789, 432.123456, 0, 0x04B, 01000, 0b1000]
70
+ expected = -719.859568
71
+ mean = a.mean
72
+ assert_kind_of(Float, mean, ".mean did not return a Float")
73
+ assert_equal(mean, expected, ".mean is not returning the correct mean")
74
+ end
75
+
76
+ def test_non_numeric_mean
77
+ assert_exception_message_correct_non_numeric_mean ["a", "b", "c"]
78
+ assert_exception_message_correct_non_numeric_mean ["1", "2", "c"]
79
+ assert_exception_message_correct_non_numeric_mean [1, 2, "c", 4]
80
+ assert_exception_message_correct_non_numeric_mean [1, 2, "3", 4]
81
+ assert_exception_message_correct_non_numeric_mean [1, nil, 3, 4]
82
+ assert_exception_message_correct_non_numeric_mean [1, false, true, 4]
83
+ end
84
+
85
+ def assert_exception_message_correct_non_numeric_mean(array)
86
+ exception = assert_raise(TypeError) {array.mean}
87
+ assert_equal("Cannot determine the mean of an array that contains non-Numeric objects.", exception.message)
88
+ end
89
+
90
+ def test_sum
91
+ a = (1 .. 6).to_a
92
+ expected = 21
93
+ sum = a.sum
94
+ assert_kind_of(Integer, sum, ".sum did not return a Integer")
95
+ assert_equal(sum, expected, ".sum is not returning the correct sum")
96
+ end
97
+
98
+ def test_sum_floats
99
+ a = (1 .. 6).to_a
100
+ a << 4.32
101
+ expected = 25.32
102
+ sum = a.sum
103
+ assert_kind_of(Float, sum, ".sum did not return a Float")
104
+ assert_equal(sum, expected, ".sum is not returning the correct sum")
105
+ end
106
+
107
+ def test_sum_non_numeric
108
+ a = (1 .. 6).to_a
109
+ a << "4.32"
110
+ exception = assert_raise(TypeError) {a.sum}
111
+ assert_equal("Array contained non-numeric non-nil elements; cannot sum contents.", exception.message)
112
+ end
113
+
114
+ def test_sum_with_nil
115
+ a = (1 .. 6).to_a
116
+ a << nil
117
+ a << 4.32
118
+ a << -26
119
+ expected = -0.68
120
+ sum = a.sum.signif(8) # need to work around floating-point precision issues
121
+ assert_kind_of(Float, sum, ".sum did not return a Float")
122
+ assert_equal(sum, expected, ".sum is not returning the correct sum")
123
+ end
124
+
125
+ def test_insert_flat
126
+ a = [1, 2, 3]
127
+ b = [4, 5]
128
+ expected = [4, 5, 1, 2, 3]
129
+ a.insert_flat(0, b)
130
+ assert_equal(expected, a, ".insert_flat failed")
131
+ end
132
+
133
+ def test_insert_flat_preserving_subarrays
134
+ a = [1, [2.1, 2.2], 3]
135
+ b = [4, 5]
136
+ expected = [1, [2.1, 2.2], 4, 5, 3]
137
+ a.insert_flat(-2, b)
138
+ assert_equal(expected.size, a.size, ".insert_flat failed to preserve preexisting subarray")
139
+ assert_equal(expected, a, ".insert_flat failed")
140
+ end
141
+
142
+ def test_all_kind_of
143
+ a = ["A string", :smybol, false, 1]
144
+ assert_false(a.all_kind_of?(String), ".all_kind_of? returned true when there were distinctly different types in the array")
145
+ assert(a.all_kind_of?(Object), ".all_kind_of? returned true when there were distinctly different types in the array")
146
+
147
+ b = (1 .. 4).to_a
148
+ assert(b.all_kind_of?(Numeric), ".all_kind_of? returned false when the array's contents were all subclasses of the questioned class")
149
+ assert(b.all_kind_of?(Integer), ".all_kind_of? returned false when the array's contents were all subclasses of the questioned class")
150
+ assert(b.all_kind_of?(Fixnum), ".all_kind_of? returned false when the array's contents were all instances of the questioned class")
151
+
152
+ b.insert(2, 2.0)
153
+ assert(b.all_kind_of?(Numeric), ".all_kind_of? returned false when the array's contents were all subclasses of the questioned class")
154
+ assert_false(b.all_kind_of?(Integer), ".all_kind_of? returned true when there were distinctly different types in the array")
155
+ assert_false(b.all_kind_of?(Fixnum), ".all_kind_of? returned true when there were distinctly different types in the array")
156
+ end
157
+
158
+
159
+ def test_all_instance_of
160
+ a = ["A string", :smybol, false, 1]
161
+ assert_false(a.all_instance_of?(String), ".all_instance_of? returned true when there were distinctly different types in the array")
162
+ assert_false(a.all_instance_of?(Object), ".all_instance_of? returned true when there were distinctly different types in the array")
163
+
164
+ b = (1 .. 4).to_a
165
+ assert_false(b.all_instance_of?(Numeric), ".all_instance_of? returned true when the array's contents were all subclasses of the questioned class")
166
+ assert_false(b.all_instance_of?(Integer), ".all_instance_of? returned true when the array's contents were all subclasses of the questioned class")
167
+ assert(b.all_instance_of?(Fixnum), ".all_instance_of? returned false when the array's contents were all instances of the questioned class")
168
+
169
+ b.insert(2, 2.0)
170
+ assert_false(b.all_instance_of?(Numeric), ".all_instance_of? returned true when the array's contents were all subclasses of the questioned class")
171
+ end
172
+
173
+ def test_wrap_fetch
174
+ a = [:a, :b, :c, :d]
175
+ assert_equal(:a, a.wrap_fetch(0), "wrap_fetch failed")
176
+ assert_equal(:d, a.wrap_fetch(3), "wrap_fetch failed")
177
+ assert_equal(:d, a.wrap_fetch(-1), "wrap_fetch failed")
178
+ assert_equal(:a, a.wrap_fetch(-4), "wrap_fetch failed")
179
+ assert_equal(:a, a.wrap_fetch(4), "wrap_fetch failed")
180
+ assert_equal(:b, a.wrap_fetch(5), "wrap_fetch failed")
181
+ assert_equal(:c, a.wrap_fetch(494), "wrap_fetch failed")
182
+ assert_equal(:c, a.wrap_fetch(-494), "wrap_fetch failed")
183
+
184
+ b = []
185
+ assert_nil(b.wrap_fetch(0), "wrap_fetch failed")
186
+ end
187
+
188
+ def test_modulo_fetch
189
+ a = [:a, :b, :c, :d]
190
+ assert_equal(:b, a.modulo_fetch(5), "modulo_fetch failed")
191
+ end
192
+
193
+ end
@@ -0,0 +1,51 @@
1
+ require "test/unit"
2
+ require_relative "../lib/more_ruby"
3
+
4
+ class TestArray < Test::Unit::TestCase
5
+
6
+ def test_signif_digits
7
+ a = []
8
+ a << {:raw => 2326759, :digits => 2, :pro => 2300000}
9
+ a << {:raw => 2326759, :digits => 3, :pro => 2330000}
10
+ a << {:raw => 2326759, :digits => 4, :pro => 2327000}
11
+ a << {:raw => 2326759, :digits => 5, :pro => 2326800}
12
+ a << {:raw => 2326759, :digits => 6, :pro => 2326760}
13
+ a << {:raw => 2326759, :digits => 7, :pro => 2326759}
14
+ a << {:raw => 2326759, :digits => 8, :pro => 2326759}
15
+ a << {:raw => 23, :digits => 3, :pro => 23}
16
+ a << {:raw => 23, :digits => 2, :pro => 23}
17
+ a << {:raw => 23, :digits => 1, :pro => 20}
18
+ a << {:raw => 23, :digits => 0, :pro => 0}
19
+ a << {:raw => 10.546, :digits => 0, :pro => 0}
20
+ a << {:raw => 10.546, :digits => 1, :pro => 10.0}
21
+ a << {:raw => 10.546, :digits => 2, :pro => 10.0}
22
+ a << {:raw => 10.546, :digits => 3, :pro => 10.5}
23
+ a << {:raw => 10.546, :digits => 4, :pro => 10.55}
24
+ a << {:raw => 10.546, :digits => 5, :pro => 10.546}
25
+ a << {:raw => 10.546, :digits => 6, :pro => 10.546}
26
+ a << {:raw => 0.766, :digits => 2, :pro => 0.77}
27
+ a << {:raw => 0.00000766, :digits => 4, :pro => 0.00000766}
28
+ a << {:raw => 0.00000766, :digits => 3, :pro => 0.00000766}
29
+ a << {:raw => 0.00000766, :digits => 2, :pro => 0.0000077}
30
+ a << {:raw => 0.00000766, :digits => 1, :pro => 0.000008}
31
+ a << {:raw => 0.00000766, :digits => 0, :pro => 0}
32
+ a << {:raw => 0.0, :digits => 4, :pro => 0.0}
33
+ a << {:raw => 0.0, :digits => 1, :pro => 0.0}
34
+ a << {:raw => 0.0, :digits => 0, :pro => 0.0}
35
+ a << {:raw => 1.00000766, :digits => 8, :pro => 1.0000077}
36
+ a << {:raw => 1.00000766, :digits => 3, :pro => 1.0}
37
+ a << {:raw => 1.00000766, :digits => 2, :pro => 1.0}
38
+ a << {:raw => 1.00000766, :digits => 1, :pro => 1}
39
+ a << {:raw => 1.00000766, :digits => 0, :pro => 0}
40
+ a << {:raw => -23, :digits => 3, :pro => -23}
41
+ a << {:raw => -0.0, :digits => 1, :pro => -0.0}
42
+ a << {:raw => -2326759, :digits => 5, :pro => -2326800}
43
+ a << {:raw => -1.00000766, :digits => 8, :pro => -1.0000077}
44
+
45
+ a.each do |x|
46
+ processed = x[:raw].signif(x[:digits])
47
+ assert_equal(x[:pro], processed, ".signif did not produce the expected result; for digit-count of #{x[:digits]} with #{x[:raw]}, expected #{x[:pro]} but received #{processed}")
48
+ end
49
+ end
50
+
51
+ end
@@ -0,0 +1,27 @@
1
+ require "test/unit"
2
+ require "test/unit"
3
+ require_relative "../lib/more_ruby"
4
+
5
+ class TestArray < Test::Unit::TestCase
6
+
7
+ def test_format_with_thousands_delimiter
8
+ a = []
9
+ a << {:raw => 234, :expected => "234"}
10
+ a << {:raw => 2326759, :expected => "2,326,759"}
11
+ a << {:raw => 2326759, :expected => "2.326.759", :delimiter => "."}
12
+ a << {:raw => 2326759, :expected => "2.-.326.-.759", :delimiter => ".-."}
13
+ a << {:raw => 2326759.123456, :expected => "2,326,759.123456"}
14
+ a << {:raw => -2326759.123456, :expected => "-2,326,759.123456"}
15
+ a << {:raw => 0.23456, :expected => "0.23456"}
16
+
17
+ a.each do |x|
18
+ if x[:delimiter]
19
+ processed = x[:raw].format_with_thousands_delimiter(x[:delimiter])
20
+ else
21
+ processed = x[:raw].format_with_thousands_delimiter
22
+ end
23
+ assert_equal(x[:expected], processed, ".format_with_thousands_delimiter did not produce the expected result; delimiter? #{x[:delimiter] != nil ? x[:delimiter] : "<none>"} with #{x[:raw]}, expected #{x[:expected]} but received #{processed}")
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,102 @@
1
+ require "test/unit"
2
+ require_relative "../lib/more_ruby"
3
+
4
+ class TestString < Test::Unit::TestCase
5
+
6
+ def test_capitalize_first_letter_only
7
+ input = "someThingELSE"
8
+ expected = "SomeThingELSE"
9
+ actual = input.capitalize_first_letter_only
10
+ assert_equal(expected, actual, ".capitalize_first_letter_only is not behaving correctly")
11
+ end
12
+
13
+ def test_capitalize_first_letter_only_single_letter
14
+ input = "s"
15
+ expected = "S"
16
+ actual = input.capitalize_first_letter_only
17
+ assert_equal(expected, actual, ".capitalize_first_letter_only is not behaving correctly")
18
+ end
19
+
20
+ def test_capitalize_first_letter_only_empty_string
21
+ input = ""
22
+ expected = ""
23
+ actual = input.capitalize_first_letter_only
24
+ assert_equal(expected, actual, ".capitalize_first_letter_only is not behaving correctly")
25
+ end
26
+
27
+ def test_escape_into_regex
28
+ s = "some s\\tring"
29
+ s2 = s.clone
30
+ e = s.escape
31
+
32
+ re = Regexp.new(e)
33
+
34
+ assert_equal(s, s2, ".escape modified the original string")
35
+ assert_not_equal(e, s, ".escape didn't escape parts of the string")
36
+
37
+ assert_equal(re =~ s, 0, ".escape didn't yield an escaped string that could be used to make a Regexp object")
38
+ assert_nil(re =~ e, ".escape yielded an escaped string that matched its Regexp object")
39
+ end
40
+
41
+ def test_snakecase
42
+ a = []
43
+ a << {:raw => "thiNGS", :expected => "thiNGS"}
44
+ a << {:raw => "thiNGS-with_stuff", :expected => "thiNGS_with_stuff"}
45
+ a << {:raw => "thi--_-ngs", :expected => "thi_ngs"}
46
+ a << {:raw => "th2i<>n!!!gs", :expected => "th2i_n_gs"}
47
+
48
+ a.each do |x|
49
+ actual = x[:raw].snakecase
50
+ assert_equal(actual, x[:expected], ".snakecase didn't work properly")
51
+ end
52
+
53
+ end
54
+
55
+ def test_snakecase_and_downcase
56
+ a = []
57
+ a << {:raw => "thiNGS", :expected => "things"}
58
+ a << {:raw => "thiNGS-with_stuff", :expected => "things_with_stuff"}
59
+ a << {:raw => "thi--_-ngs", :expected => "thi_ngs"}
60
+ a << {:raw => "th2i<>n!!!gs", :expected => "th2i_n_gs"}
61
+
62
+ a.each do |x|
63
+ actual = x[:raw].snakecase_and_downcase
64
+ assert_equal(actual, x[:expected], "snakecase_and_downcase didn't work properly")
65
+ end
66
+
67
+ end
68
+
69
+ def test_pascalcase
70
+ a = []
71
+ a << {:raw => "thiNGS", :expected => "Things"}
72
+ a << {:raw => "thiNGS-with_stuff", :expected => "ThingsWithStuff"}
73
+ a << {:raw => "thi--_-ngs", :expected => "ThiNgs"}
74
+ a << {:raw => "th2i<>n!!!gs", :expected => "Th2iNGs"}
75
+ a << {:raw => "a_and_b", :expected => "AAndB"}
76
+ a << {:raw => "A_AND_B", :expected => "AAndB"}
77
+ a << {:raw => "AAndB", :expected => "Aandb"}
78
+
79
+ a.each do |x|
80
+ actual = x[:raw].pascalcase
81
+ assert_equal(x[:expected], actual, ".pascalcase didn't work properly")
82
+ end
83
+
84
+ end
85
+
86
+ def test_camelcase
87
+ a = []
88
+ a << {:raw => "thiNGS", :expected => "things"}
89
+ a << {:raw => "thiNGS-with_stuff", :expected => "thingsWithStuff"}
90
+ a << {:raw => "thi--_-ngs", :expected => "thiNgs"}
91
+ a << {:raw => "th2i<>n!!!gs", :expected => "th2iNGs"}
92
+ a << {:raw => "a_and_b", :expected => "aAndB"}
93
+ a << {:raw => "A_AND_B", :expected => "aAndB"}
94
+ a << {:raw => "AAndB", :expected => "aandb"}
95
+
96
+ a.each do |x|
97
+ actual = x[:raw].camelcase
98
+ assert_equal( x[:expected], actual, ".camelcase didn't work properly")
99
+ end
100
+
101
+ end
102
+ end
@@ -0,0 +1,16 @@
1
+ require "test/unit"
2
+ require_relative "../lib/more_ruby"
3
+
4
+ class TestArray < Test::Unit::TestCase
5
+
6
+ def test_remove_subseconds
7
+ t = Time.now
8
+ t2 = t.remove_subseconds
9
+
10
+ assert_not_equal(t, t2, "remove_subseconds didn't work")
11
+ assert_equal(t2.subsec.to_s, "0", "remove_subseconds didn't work")
12
+ assert_equal(t2.usec.to_s, "0", "remove_subseconds didn't work")
13
+
14
+ end
15
+
16
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: more_ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Richard Morrisby
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-05-04 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: " A very simple gem that adds some methods to some Ruby standard classes,
14
+ e.g. <array>.include_any?, <array>.delete_random, etc.\n\n Simply require the gem
15
+ ( require \"more_ruby\" ) and the additional methods will be available.\n \n #
16
+ New instance methods #\n\n ## Array\n :all_instance_of?, :all_kind_of?, :av, :delete_random,
17
+ :include_any?, :insert_flat, :mean, :modulo_fetch, :peach, :random, :random_index,
18
+ :random_insert, :random_move, :stringify_all_values_deep, :sum, :wrap_fetch\n \n
19
+ \ ## Fixnum\n :digit_count, :format_with_thousands_delimiter, :num_to_letter, :signif\n
20
+ \ \n ## Float\n :format_with_thousands_delimiter, :signif\n \n ## Hash\n :all_keys,
21
+ :all_values, :delete_random, :peach, :random_key, :random_pair, :random_value, :remove_empty_fields,
22
+ :sort_deep, :stringify_all_values_deep, :strip_hash_of_keys, :to_a_deep, :to_xml\n
23
+ \ \n ## Integer\n :digit_count, :format_with_thousands_delimiter, :signif\n \n
24
+ \ ## NilClass\n :empty?\n \n ## Numeric\n :format_with_thousands_delimiter\n
25
+ \ \n ## String\n :append, :camelcase, :camelcase_to_snakecase, :capitalize_all,
26
+ :capitalize_first_letter_only, :escape, :escape_whitespace, :extract_values_from_xml_string,
27
+ :formatted_number, :index_of_last_capital, :invert_case, :is_hex?, :is_integer?,
28
+ :join, :pascalcase, :prefix_lines, :random_case, :snakecase, :snakecase_and_downcase,
29
+ :to_bool, :unindent\n \n ## Time\n :is_after?, :is_before?, :is_within?, :remove_subseconds\n
30
+ \ \n # New singleton methods #\n \n ## FalseClass\n :maybe?, :random\n \n ##
31
+ File\n :basename_no_ext\n \n ## TrueClass\n :maybe?, :random\n\n"
32
+ email: rmorrisby@gmail.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - LICENCE.txt
38
+ - README.md
39
+ - lib/more_ruby.rb
40
+ - lib/more_ruby/array.rb
41
+ - lib/more_ruby/enumerable.rb
42
+ - lib/more_ruby/falseclass.rb
43
+ - lib/more_ruby/file.rb
44
+ - lib/more_ruby/fixnum.rb
45
+ - lib/more_ruby/float.rb
46
+ - lib/more_ruby/hash.rb
47
+ - lib/more_ruby/integer.rb
48
+ - lib/more_ruby/nilclass.rb
49
+ - lib/more_ruby/numeric.rb
50
+ - lib/more_ruby/string.rb
51
+ - lib/more_ruby/time.rb
52
+ - lib/more_ruby/trueclass.rb
53
+ - test/test_array.rb
54
+ - test/test_integer.rb
55
+ - test/test_numeric.rb
56
+ - test/test_string.rb
57
+ - test/test_time.rb
58
+ homepage: https://rubygems.org/gems/more_ruby
59
+ licenses:
60
+ - MIT
61
+ metadata: {}
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '1.9'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubygems_version: 3.0.3
78
+ signing_key:
79
+ specification_version: 4
80
+ summary: Adds some extra methods to some Ruby standard classes
81
+ test_files:
82
+ - test/test_array.rb
83
+ - test/test_integer.rb
84
+ - test/test_numeric.rb
85
+ - test/test_string.rb
86
+ - test/test_time.rb