more_core_extensions 3.1.1 → 3.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.
- checksums.yaml +4 -4
- data/README.md +4 -0
- data/lib/more_core_extensions/core_ext/array/tableize.rb +83 -38
- data/lib/more_core_extensions/core_ext/numeric.rb +1 -0
- data/lib/more_core_extensions/core_ext/numeric/clamp.rb +18 -0
- data/lib/more_core_extensions/core_ext/string.rb +1 -0
- data/lib/more_core_extensions/core_ext/string/formats.rb +1 -1
- data/lib/more_core_extensions/core_ext/string/hex_dump.rb +38 -26
- data/lib/more_core_extensions/core_ext/string/iec60027_2.rb +19 -0
- data/lib/more_core_extensions/version.rb +1 -1
- data/spec/core_ext/numeric/clamp_spec.rb +17 -0
- data/spec/core_ext/string/formats_spec.rb +2 -0
- data/spec/core_ext/string/iec60027_2_spec.rb +13 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a1add9ba7e2ca9ea1cd89792999f0a40b1ae00a0
|
4
|
+
data.tar.gz: 21149cb02025e1c91ad29e50a68bc4df68746808
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 40638498bbcb894d6722018c78c9ce10eecb32eb7a64b60233735c6f442cc8a18d3685020348db60fb658a0c8b6f3bcc7cd4e6ead1cb407355ff9298c1758374
|
7
|
+
data.tar.gz: 8644345821bb5bef19fecd89e4e5575dd36ff6210146cfcbd029a2dd9310c607b7ad4ca1bf0e6776ff1fa2ddbfb402ce6c052b4d08978cba5a9ee7fee4bbbf82
|
data/README.md
CHANGED
@@ -59,6 +59,8 @@ MoreCoreExtensions are a set of core extensions beyond those provided by ActiveS
|
|
59
59
|
|
60
60
|
#### Numeric
|
61
61
|
|
62
|
+
* core_ext/numeric/clamp.rb
|
63
|
+
* `#clamp` - Clamp a number to a minimum and/or maximum value
|
62
64
|
* core_ext/numeric/math.rb
|
63
65
|
* `#square` - Returns the square of a Numeric
|
64
66
|
* core_ext/numeric/rounding.rb
|
@@ -82,6 +84,8 @@ MoreCoreExtensions are a set of core extensions beyond those provided by ActiveS
|
|
82
84
|
* `#guid?` - Returns whether or not the String is a valid GUID
|
83
85
|
* core_ext/string/hex_dump.rb
|
84
86
|
* `#hex_dump` - Dumps the string in a hex editor style format
|
87
|
+
* core_ext/string/iec60027_2.rb
|
88
|
+
* `#iec_60027_2_to_i` - Convert strings with an IEC60027-2 suffix to an integer
|
85
89
|
|
86
90
|
#### Shared
|
87
91
|
|
@@ -31,59 +31,104 @@ module MoreCoreExtensions
|
|
31
31
|
# Value3 | Value4
|
32
32
|
#
|
33
33
|
def tableize(options = {})
|
34
|
-
|
35
|
-
when Array; tableize_arrays(options)
|
36
|
-
when Hash; tableize_hashes(options)
|
37
|
-
else raise "must be an Array of Arrays or Array of Hashes"
|
38
|
-
end
|
34
|
+
Tableizer.new(self, options).tableize
|
39
35
|
end
|
40
36
|
|
41
|
-
private
|
37
|
+
# This class is a private implementation and not part of the public API.
|
38
|
+
class Tableizer
|
39
|
+
attr_accessor :target, :options
|
42
40
|
|
43
|
-
|
44
|
-
|
41
|
+
def initialize(target, options)
|
42
|
+
@target = target
|
43
|
+
@options = options
|
44
|
+
end
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
46
|
+
def tableize
|
47
|
+
case target.first
|
48
|
+
when Array then tableize_arrays
|
49
|
+
when Hash then tableize_hashes
|
50
|
+
else raise "must be an Array of Arrays or Array of Hashes"
|
51
|
+
end
|
52
|
+
end
|
52
53
|
|
53
|
-
|
54
|
+
private
|
55
|
+
|
56
|
+
def tableize_hashes
|
57
|
+
# Convert the target to an Array of Arrays
|
58
|
+
keys = options[:columns] || columns_from_hash_keys
|
59
|
+
self.target = target.collect { |h| h.values_at(*keys) }.unshift(keys)
|
60
|
+
options[:header] = true
|
61
|
+
|
62
|
+
tableize_arrays
|
63
|
+
end
|
64
|
+
|
65
|
+
def columns_from_hash_keys
|
66
|
+
target.first.keys.sort_by(&:to_s).tap do |keys|
|
67
|
+
apply_leading_columns!(keys)
|
68
|
+
apply_trailing_columns!(keys)
|
54
69
|
end
|
55
70
|
end
|
56
71
|
|
57
|
-
|
72
|
+
def apply_leading_columns!(keys)
|
73
|
+
return unless options[:leading_columns]
|
74
|
+
options[:leading_columns].reverse_each { |h| keys.unshift(keys.delete(h)) }
|
75
|
+
end
|
76
|
+
|
77
|
+
def apply_trailing_columns!(keys)
|
78
|
+
return unless options[:trailing_columns]
|
79
|
+
options[:trailing_columns].each { |h| keys.push(keys.delete(h)) }
|
80
|
+
end
|
81
|
+
|
82
|
+
def tableize_arrays
|
83
|
+
options[:header] = true unless options.key?(:header)
|
58
84
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
85
|
+
widths, justifications = widths_and_justifications
|
86
|
+
table = target.collect { |row| format_row(row, widths, justifications) }
|
87
|
+
format_table(table, widths)
|
88
|
+
end
|
89
|
+
|
90
|
+
def widths_and_justifications
|
91
|
+
widths = []
|
92
|
+
justifications = []
|
93
|
+
|
94
|
+
target.each do |row|
|
95
|
+
row.each.with_index do |field, field_i|
|
96
|
+
apply_width!(widths, field, field_i)
|
97
|
+
apply_justification!(justifications, field, field_i)
|
98
|
+
end
|
64
99
|
end
|
65
|
-
r = " #{r.join(' | ')} ".rstrip
|
66
100
|
|
67
|
-
|
68
|
-
|
101
|
+
return widths, justifications
|
102
|
+
end
|
103
|
+
|
104
|
+
def apply_width!(widths, field, field_i)
|
105
|
+
widths[field_i] = [widths[field_i].to_i, field.to_s.length].max
|
106
|
+
widths[field_i] = [options[:max_width], widths[field_i].to_i].min if options[:max_width]
|
107
|
+
end
|
108
|
+
|
109
|
+
def apply_justification!(justifications, field, field_i)
|
110
|
+
justifications[field_i] = field.kind_of?(Numeric) ? "" : "-"
|
111
|
+
end
|
112
|
+
|
113
|
+
def format_row(row, widths, justifications)
|
114
|
+
formatted_fields = row.collect.with_index do |field, field_i|
|
115
|
+
format_field(field, widths[field_i], justifications[field_i])
|
116
|
+
end
|
117
|
+
" #{formatted_fields.join(' | ')} ".rstrip
|
69
118
|
end
|
70
|
-
table.join("\n") << "\n"
|
71
|
-
end
|
72
119
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
elsif options[:leading_columns] || options[:trailing_columns]
|
77
|
-
keys = self.first.keys.sort_by(&:to_s)
|
78
|
-
options[:leading_columns].reverse.each { |h| keys.unshift(keys.delete(h)) } if options[:leading_columns]
|
79
|
-
options[:trailing_columns].each { |h| keys.push(keys.delete(h)) } if options[:trailing_columns]
|
80
|
-
else
|
81
|
-
keys = self.first.keys.sort_by(&:to_s)
|
120
|
+
def format_field(field, width, justification)
|
121
|
+
field = field.to_s.gsub(/\n|\r/, '').slice(0, width)
|
122
|
+
"%0#{justification}#{width}s" % field
|
82
123
|
end
|
83
124
|
|
84
|
-
|
85
|
-
|
86
|
-
|
125
|
+
def format_table(table, widths)
|
126
|
+
if options[:header] && table.size > 1
|
127
|
+
header_separator = widths.collect { |w| "-" * (w + 2) }.join("+")
|
128
|
+
table.insert(1, header_separator)
|
129
|
+
end
|
130
|
+
table.join("\n") << "\n"
|
131
|
+
end
|
87
132
|
end
|
88
133
|
end
|
89
134
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module MoreCoreExtensions
|
2
|
+
module NumericClamp
|
3
|
+
#
|
4
|
+
# Clamp a number to a minimum and/or maximum value.
|
5
|
+
#
|
6
|
+
# 8.clamp(nil, nil) #=> 8
|
7
|
+
# 8.clamp(9, nil) #=> 9
|
8
|
+
# 8.clamp(nil, 6) #=> 6
|
9
|
+
def clamp(min, max)
|
10
|
+
value = self
|
11
|
+
value = [value, min].max if min
|
12
|
+
value = [value, max].min if max
|
13
|
+
value
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
Numeric.send(:prepend, MoreCoreExtensions::NumericClamp)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module MoreCoreExtensions
|
2
2
|
module StringFormats
|
3
3
|
# From: http://www.regular-expressions.info/email.html
|
4
|
-
RE_EMAIL = %r{\A[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\z}
|
4
|
+
RE_EMAIL = %r{\A[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\z}i
|
5
5
|
|
6
6
|
def email?
|
7
7
|
!!(self =~ RE_EMAIL)
|
@@ -9,47 +9,59 @@ module MoreCoreExtensions
|
|
9
9
|
# instead of returning as a string.
|
10
10
|
# :meth:: Used in conjunction with _:obj_ to send each line to an object
|
11
11
|
# instead of returning as a string.
|
12
|
-
def hex_dump(
|
13
|
-
|
14
|
-
|
12
|
+
def hex_dump(options = {})
|
13
|
+
HexDumper.new(self, options).dump
|
14
|
+
end
|
15
|
+
|
16
|
+
# This class is a private implementation and not part of the public API.
|
17
|
+
class HexDumper
|
18
|
+
attr_reader :target, :options
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
|
20
|
+
DEFAULT_OPTIONS = {
|
21
|
+
:grouping => 16,
|
22
|
+
:newline => true,
|
23
|
+
:start_pos => 0
|
24
|
+
}.freeze
|
19
25
|
|
20
|
-
|
26
|
+
def initialize(target, options)
|
27
|
+
@target = target
|
28
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
21
29
|
|
22
|
-
|
23
|
-
|
30
|
+
if !!options[:obj] ^ !!options[:meth] # rubocop:disable Style/DoubleNegation
|
31
|
+
raise ArgumentError, "obj and meth must both be set, or both not set"
|
32
|
+
end
|
33
|
+
end
|
24
34
|
|
25
|
-
|
26
|
-
|
27
|
-
row_chars = ''
|
35
|
+
def dump
|
36
|
+
obj, meth, grouping, pos = options.values_at(:obj, :meth, :grouping, :start_pos)
|
28
37
|
|
29
|
-
|
30
|
-
row_vals << c
|
31
|
-
row_chars << (c < 0x20 || (c >= 0x7F && c < 0xA0) ? '.' : c.chr)
|
38
|
+
ret = ""
|
32
39
|
|
33
|
-
|
34
|
-
|
40
|
+
target.each_byte.each_slice(grouping) do |bytes|
|
41
|
+
row = format_row(pos, bytes)
|
42
|
+
ret << row
|
35
43
|
|
36
|
-
row_vals.unshift(pos)
|
37
|
-
ret << (row_format % row_vals) << row_chars
|
38
|
-
ret << "\n" if newline
|
39
44
|
if obj
|
40
|
-
obj.send(meth,
|
41
|
-
ret
|
45
|
+
obj.send(meth, row)
|
46
|
+
ret = ""
|
42
47
|
end
|
43
48
|
|
44
49
|
pos += grouping
|
45
|
-
row_vals.clear
|
46
|
-
row_chars = ''
|
47
50
|
end
|
48
51
|
|
49
|
-
|
52
|
+
ret
|
50
53
|
end
|
51
54
|
|
52
|
-
|
55
|
+
def format_row(pos, bytes)
|
56
|
+
padding = " " * (options[:grouping] - bytes.size)
|
57
|
+
byte_chars = bytes.collect { |byte| row_char(byte) }.join
|
58
|
+
newline = "\n" if options[:newline]
|
59
|
+
"0x%08x #{"%02x " * bytes.size}#{padding} " % [pos, *bytes] << "#{byte_chars}#{newline}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def row_char(byte)
|
63
|
+
byte < 0x20 || (byte >= 0x7F && byte < 0xA0) ? '.' : byte.chr
|
64
|
+
end
|
53
65
|
end
|
54
66
|
end
|
55
67
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module MoreCoreExtensions
|
2
|
+
module IEC60027_2
|
3
|
+
# Support converting strings with an IEC60027-2 suffix to an integer
|
4
|
+
# http://physics.nist.gov/cuu/Units/binary.html
|
5
|
+
# Example: "1 Ki".iec_60027_2_to_i => 1024
|
6
|
+
|
7
|
+
IEC_60027_2_SIZE_SUFFIXES = %w(Ki Mi Gi Ti Pi Ei Zi Yi).freeze
|
8
|
+
def iec_60027_2_to_i
|
9
|
+
suffix_index = IEC_60027_2_SIZE_SUFFIXES.index(self[-2..-1])
|
10
|
+
if suffix_index.nil?
|
11
|
+
Integer(self)
|
12
|
+
else
|
13
|
+
Integer(self[0..-3]) * (2**10)**(suffix_index + 1)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
String.send(:prepend, MoreCoreExtensions::IEC60027_2)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
describe Numeric do
|
2
|
+
it "#clamp" do
|
3
|
+
expect(8.clamp(nil, nil)).to eq(8)
|
4
|
+
expect(8.clamp(3, nil)).to eq(8)
|
5
|
+
expect(8.clamp(13, nil)).to eq(13)
|
6
|
+
expect(8.clamp(nil, 6)).to eq(6)
|
7
|
+
expect(8.clamp(13, 16)).to eq(13)
|
8
|
+
expect(20.clamp(13, 16)).to eq(16)
|
9
|
+
|
10
|
+
expect(8.0.clamp(nil, nil)).to eq(8.0)
|
11
|
+
expect(8.0.clamp(3.0, nil)).to eq(8.0)
|
12
|
+
expect(8.0.clamp(13.0, nil)).to eq(13.0)
|
13
|
+
expect(8.0.clamp(nil, 6.0)).to eq(6.0)
|
14
|
+
expect(8.0.clamp(13.0, 16.0)).to eq(13.0)
|
15
|
+
expect(20.0.clamp(13.0, 16.0)).to eq(16.0)
|
16
|
+
end
|
17
|
+
end
|
@@ -4,6 +4,8 @@ describe String do
|
|
4
4
|
expect("john.doe@example.com").to be_email
|
5
5
|
expect("john.doe@my-company.prestidigitation").to be_email
|
6
6
|
expect("john.o'doe@example.com").to be_email
|
7
|
+
expect("john.doe@EXAMPLE.COM").to be_email
|
8
|
+
expect("John.Doe@example.com").to be_email
|
7
9
|
|
8
10
|
expect("john\ndoe@example.com").not_to be_email
|
9
11
|
expect("").not_to be_email
|
@@ -0,0 +1,13 @@
|
|
1
|
+
describe String do
|
2
|
+
it '#iec60027_2' do
|
3
|
+
expect("1 ".iec_60027_2_to_i).to eq(1)
|
4
|
+
expect("1 Ki".iec_60027_2_to_i).to eq(1_024)
|
5
|
+
expect("1 Mi".iec_60027_2_to_i).to eq(1_048_576)
|
6
|
+
expect("1 Gi".iec_60027_2_to_i).to eq(1_073_741_824)
|
7
|
+
expect("1 Ti".iec_60027_2_to_i).to eq(1_099_511_627_776)
|
8
|
+
expect("1 Pi".iec_60027_2_to_i).to eq(1_125_899_906_842_624)
|
9
|
+
expect("1 Ei".iec_60027_2_to_i).to eq(1_152_921_504_606_846_976)
|
10
|
+
expect("1 Zi".iec_60027_2_to_i).to eq(1_180_591_620_717_411_303_424)
|
11
|
+
expect("1 Yi".iec_60027_2_to_i).to eq(1_208_925_819_614_629_174_706_176)
|
12
|
+
end
|
13
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: more_core_extensions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason Frey
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2017-03-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -111,6 +111,7 @@ files:
|
|
111
111
|
- lib/more_core_extensions/core_ext/module.rb
|
112
112
|
- lib/more_core_extensions/core_ext/module/namespace.rb
|
113
113
|
- lib/more_core_extensions/core_ext/numeric.rb
|
114
|
+
- lib/more_core_extensions/core_ext/numeric/clamp.rb
|
114
115
|
- lib/more_core_extensions/core_ext/numeric/math.rb
|
115
116
|
- lib/more_core_extensions/core_ext/numeric/rounding.rb
|
116
117
|
- lib/more_core_extensions/core_ext/object.rb
|
@@ -119,6 +120,7 @@ files:
|
|
119
120
|
- lib/more_core_extensions/core_ext/string.rb
|
120
121
|
- lib/more_core_extensions/core_ext/string/formats.rb
|
121
122
|
- lib/more_core_extensions/core_ext/string/hex_dump.rb
|
123
|
+
- lib/more_core_extensions/core_ext/string/iec60027_2.rb
|
122
124
|
- lib/more_core_extensions/version.rb
|
123
125
|
- spec/core_ext/array/deletes_spec.rb
|
124
126
|
- spec/core_ext/array/duplicates_spec.rb
|
@@ -131,11 +133,13 @@ files:
|
|
131
133
|
- spec/core_ext/array/tableize_spec.rb
|
132
134
|
- spec/core_ext/hash/deletes_spec.rb
|
133
135
|
- spec/core_ext/hash/nested_spec.rb
|
136
|
+
- spec/core_ext/numeric/clamp_spec.rb
|
134
137
|
- spec/core_ext/numeric/math_spec.rb
|
135
138
|
- spec/core_ext/numeric/rounding_spec.rb
|
136
139
|
- spec/core_ext/object/namespace_spec.rb
|
137
140
|
- spec/core_ext/string/formats_spec.rb
|
138
141
|
- spec/core_ext/string/hex_dump_spec.rb
|
142
|
+
- spec/core_ext/string/iec60027_2_spec.rb
|
139
143
|
- spec/spec_helper.rb
|
140
144
|
homepage: http://github.com/ManageIQ/more_core_extensions
|
141
145
|
licenses:
|
@@ -174,10 +178,12 @@ test_files:
|
|
174
178
|
- spec/core_ext/array/tableize_spec.rb
|
175
179
|
- spec/core_ext/hash/deletes_spec.rb
|
176
180
|
- spec/core_ext/hash/nested_spec.rb
|
181
|
+
- spec/core_ext/numeric/clamp_spec.rb
|
177
182
|
- spec/core_ext/numeric/math_spec.rb
|
178
183
|
- spec/core_ext/numeric/rounding_spec.rb
|
179
184
|
- spec/core_ext/object/namespace_spec.rb
|
180
185
|
- spec/core_ext/string/formats_spec.rb
|
181
186
|
- spec/core_ext/string/hex_dump_spec.rb
|
187
|
+
- spec/core_ext/string/iec60027_2_spec.rb
|
182
188
|
- spec/spec_helper.rb
|
183
189
|
- ".rspec"
|