more_core_extensions 1.0.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/.gitignore +17 -0
- data/.rspec +2 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +63 -0
- data/Rakefile +6 -0
- data/lib/more_core_extensions/all.rb +5 -0
- data/lib/more_core_extensions/core_ext/array/duplicates.rb +11 -0
- data/lib/more_core_extensions/core_ext/array/inclusions.rb +33 -0
- data/lib/more_core_extensions/core_ext/array/random.rb +19 -0
- data/lib/more_core_extensions/core_ext/array/stretch.rb +49 -0
- data/lib/more_core_extensions/core_ext/array/tableize.rb +89 -0
- data/lib/more_core_extensions/core_ext/array.rb +5 -0
- data/lib/more_core_extensions/core_ext/hash/deletes.rb +19 -0
- data/lib/more_core_extensions/core_ext/hash/nested.rb +56 -0
- data/lib/more_core_extensions/core_ext/hash.rb +2 -0
- data/lib/more_core_extensions/core_ext/string/formats.rb +41 -0
- data/lib/more_core_extensions/core_ext/string/hex_dump.rb +55 -0
- data/lib/more_core_extensions/core_ext/string.rb +2 -0
- data/lib/more_core_extensions/version.rb +3 -0
- data/lib/more_core_extensions.rb +1 -0
- data/more_core_extensions.gemspec +27 -0
- data/spec/core_ext/array/duplicates_spec.rb +11 -0
- data/spec/core_ext/array/inclusions_spec.rb +33 -0
- data/spec/core_ext/array/stretch_spec.rb +96 -0
- data/spec/core_ext/array/tableize_spec.rb +158 -0
- data/spec/core_ext/hash/deletes_spec.rb +17 -0
- data/spec/core_ext/hash/nested_spec.rb +125 -0
- data/spec/core_ext/string/formats_spec.rb +63 -0
- data/spec/core_ext/string/hex_dump_spec.rb +86 -0
- data/spec/spec_helper.rb +21 -0
- metadata +175 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Red Hat, Inc.
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# MoreCoreExtensions
|
2
|
+
|
3
|
+
MoreCoreExtensions are a set of core extensions beyond those provided by ActiveSupport.
|
4
|
+
|
5
|
+
[](https://travis-ci.org/ManageIQ/more_core_extensions)
|
6
|
+
[](https://codeclimate.com/github/ManageIQ/more_core_extensions)
|
7
|
+
[](https://coveralls.io/r/ManageIQ/more_core_extensions)
|
8
|
+
[](https://gemnasium.com/ManageIQ/more_core_extensions)
|
9
|
+
|
10
|
+
## Extensions Provided
|
11
|
+
|
12
|
+
* Array
|
13
|
+
* duplicates
|
14
|
+
* include_any?
|
15
|
+
* include_none?
|
16
|
+
* include_all?
|
17
|
+
* random_index
|
18
|
+
* random_element
|
19
|
+
* stretch
|
20
|
+
* stretch!
|
21
|
+
* zip_stretched
|
22
|
+
* tableize
|
23
|
+
* Hash
|
24
|
+
* delete_nils
|
25
|
+
* delete_blanks
|
26
|
+
* fetch_path
|
27
|
+
* has_key_path?
|
28
|
+
* include_path?
|
29
|
+
* key_path?
|
30
|
+
* member_path?
|
31
|
+
* store_path
|
32
|
+
* delete_path
|
33
|
+
* String
|
34
|
+
* email?
|
35
|
+
* domain_name?
|
36
|
+
* ipv4?
|
37
|
+
* ipv6?
|
38
|
+
* ipaddress?
|
39
|
+
* integer?
|
40
|
+
* guid?
|
41
|
+
* hex_dump
|
42
|
+
|
43
|
+
## Installation
|
44
|
+
|
45
|
+
Add this line to your application's Gemfile:
|
46
|
+
|
47
|
+
gem 'more_core_extensions'
|
48
|
+
|
49
|
+
And then execute:
|
50
|
+
|
51
|
+
$ bundle
|
52
|
+
|
53
|
+
Or install it yourself as:
|
54
|
+
|
55
|
+
$ gem install more_core_extensions
|
56
|
+
|
57
|
+
## Contributing
|
58
|
+
|
59
|
+
1. Fork it
|
60
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
61
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
62
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
63
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
module MoreCoreExtensions::ArrayDuplicates
|
2
|
+
#
|
3
|
+
# Returns an Array of the duplicates found.
|
4
|
+
#
|
5
|
+
# [1, 2, 3, 4, 2, 4].duplicates #=> [2, 4]
|
6
|
+
def duplicates
|
7
|
+
self.inject(Hash.new(0)) { |h, v| h[v] += 1; h }.reject { |k, v| v == 1 }.keys
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
Array.send(:include, MoreCoreExtensions::ArrayDuplicates)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module MoreCoreExtensions::ArrayInclusions
|
2
|
+
#
|
3
|
+
# Returns whether the Array contains any of the items.
|
4
|
+
#
|
5
|
+
# [1, 2, 3].include_any?(1, 2) #=> true
|
6
|
+
# [1, 2, 3].include_any?(1, 4) #=> true
|
7
|
+
# [1, 2, 3].include_any?(4, 5) #=> false
|
8
|
+
def include_any?(*items)
|
9
|
+
!(self & items).empty?
|
10
|
+
end
|
11
|
+
|
12
|
+
#
|
13
|
+
# Returns whether the Array contains none of the items.
|
14
|
+
#
|
15
|
+
# [1, 2, 3].include_none?(1, 2) #=> false
|
16
|
+
# [1, 2, 3].include_none?(1, 4) #=> false
|
17
|
+
# [1, 2, 3].include_none?(4, 5) #=> true
|
18
|
+
def include_none?(*items)
|
19
|
+
(self & items).empty?
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Returns whether the Array contains all of the items.
|
24
|
+
#
|
25
|
+
# [1, 2, 3].include_all?(1, 2) #=> true
|
26
|
+
# [1, 2, 3].include_all?(1, 4) #=> false
|
27
|
+
# [1, 2, 3].include_all?(4, 5) #=> false
|
28
|
+
def include_all?(*items)
|
29
|
+
(items - self).empty?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Array.send(:include, MoreCoreExtensions::ArrayInclusions)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module MoreCoreExtensions::ArrayRandom
|
2
|
+
#
|
3
|
+
# Picks a valid index randomly
|
4
|
+
#
|
5
|
+
# [1, 2, 3, 4, 2, 4].random_index #=> random number between 0..5
|
6
|
+
def random_index
|
7
|
+
rand(self.size)
|
8
|
+
end
|
9
|
+
|
10
|
+
#
|
11
|
+
# Picks an element randomly
|
12
|
+
#
|
13
|
+
# [1, 2, 3, 4, 2, 4].random_element #=> any randomly selected element in Array
|
14
|
+
def random_element
|
15
|
+
self[self.random_index]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
Array.send(:include, MoreCoreExtensions::ArrayRandom)
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module MoreCoreExtensions::ArrayStretch
|
2
|
+
module ClassMethods
|
3
|
+
# Stretch all argument Arrays to make them the same size.
|
4
|
+
#
|
5
|
+
# Array.stretch([1, 2], [3, 4], [5, 6, 7]) #=> [[1, 2, nil], [3, 4, nil], [5, 6, 7]]
|
6
|
+
def stretch(*arys)
|
7
|
+
self.stretch!(*arys.collect { |a| a.dup })
|
8
|
+
end
|
9
|
+
|
10
|
+
# Stretch all argument Arrays to make them the same size. Modifies the arguments in place.
|
11
|
+
#
|
12
|
+
# Array.stretch!([1, 2], [3, 4], [5, 6, 7]) #=> [[1, 2, nil], [3, 4, nil], [5, 6, 7]]
|
13
|
+
def stretch!(*arys)
|
14
|
+
max_size = arys.collect { |a| a.length }.max
|
15
|
+
arys.each { |a| a[max_size - 1] = nil unless a.length == max_size }
|
16
|
+
return *arys
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Stretch receiver to be the same size as the longest argument Array.
|
21
|
+
#
|
22
|
+
# [1, 2].stretch([3, 4], [5, 6, 7]) #=> [1, 2, nil]
|
23
|
+
def stretch(*arys)
|
24
|
+
self.dup.stretch!(*arys)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Stretch receiver to be the same size as the longest argument Array. Modifies the receiver in place.
|
28
|
+
#
|
29
|
+
# [1, 2].stretch!([3, 4], [5, 6, 7]) #=> [1, 2, nil]
|
30
|
+
def stretch!(*arys)
|
31
|
+
max_size = (arys + [self]).collect { |a| a.length }.max
|
32
|
+
self[max_size - 1] = nil unless self.length == max_size
|
33
|
+
return self
|
34
|
+
end
|
35
|
+
|
36
|
+
# Zip arguments stretching the receiver if necessary. Ruby's +zip+ method
|
37
|
+
# will only zip up to the number of the receiver's elements if the receiver
|
38
|
+
# is shorter than the argument Arrays. This method will zip nils instead of
|
39
|
+
# stopping.
|
40
|
+
#
|
41
|
+
# [1, 2].zip([3, 4], [5, 6, 7]) #=> [[1, 3, 5], [2, 4, 6]]
|
42
|
+
# [1, 2].zip_stretched([3, 4], [5, 6, 7]) #=> [[1, 3, 5], [2, 4, 6], [nil, nil, 7]
|
43
|
+
def zip_stretched(*arys)
|
44
|
+
self.stretch(*arys).zip(*arys)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
Array.send(:extend, MoreCoreExtensions::ArrayStretch::ClassMethods)
|
49
|
+
Array.send(:include, MoreCoreExtensions::ArrayStretch)
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module MoreCoreExtensions::ArrayTableize
|
2
|
+
# Create a string representation of _self_ in a tabular format if self is an
|
3
|
+
# Array of Arrays or an Array of Hashes.
|
4
|
+
#
|
5
|
+
# If an Array of Hashes is passed, the headers are assumed from the keys in
|
6
|
+
# the first element of the Array, and the header option is ignored. Also,
|
7
|
+
# the headers are sorted, unless overridden with options.
|
8
|
+
#
|
9
|
+
# General options:
|
10
|
+
# ::max_width: Maximum column width, in order to limit wide columns.
|
11
|
+
#
|
12
|
+
# Options with Array of Arrays:
|
13
|
+
# ::header: Whether or not the first row of data is a header row. Default is
|
14
|
+
# true.
|
15
|
+
#
|
16
|
+
# Options with Array of Hashes:
|
17
|
+
# ::columns: An Array of keys that define the order of all columns.
|
18
|
+
# ::leading_columns: An Array of keys that should be moved to the left side
|
19
|
+
# of the table. This option is ignored if columns option
|
20
|
+
# is passed.
|
21
|
+
# ::trailing_columns: An Array of keys that should be moved to the right side
|
22
|
+
# of the table. This option is ignored if columns option
|
23
|
+
# is passed.
|
24
|
+
#
|
25
|
+
# [["Col1", "Col2"], ["Val1", "Val2"], ["Value3", "Value4"]].tableize #=>
|
26
|
+
#
|
27
|
+
# Col1 | Col2
|
28
|
+
# --------+--------
|
29
|
+
# Val1 | Val2
|
30
|
+
# Value3 | Value4
|
31
|
+
#
|
32
|
+
def tableize(options = {})
|
33
|
+
case self.first
|
34
|
+
when Array; tableize_arrays(options)
|
35
|
+
when Hash; tableize_hashes(options)
|
36
|
+
else raise "must be an Array of Arrays or Array of Hashes"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def tableize_arrays(options)
|
43
|
+
options[:header] = true unless options.has_key?(:header)
|
44
|
+
|
45
|
+
widths = []
|
46
|
+
justifications = []
|
47
|
+
self.each do |row|
|
48
|
+
row.each_with_index do |field, field_i|
|
49
|
+
widths[field_i] = [widths[field_i].to_i, field.to_s.length].max
|
50
|
+
widths[field_i] = [options[:max_width], widths[field_i].to_i].min if options[:max_width]
|
51
|
+
|
52
|
+
justifications[field_i] = field.kind_of?(Numeric) ? "" : "-"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
header_separator = widths.collect { |w| "-" * (w + 2) }.join("+")
|
57
|
+
|
58
|
+
table = []
|
59
|
+
self.each_with_index do |row, row_i|
|
60
|
+
r = []
|
61
|
+
row.each_with_index do |field, field_i|
|
62
|
+
r << sprintf("%0#{justifications[field_i]}#{widths[field_i]}s", field.to_s.gsub(/\n|\r/, '').slice(0, widths[field_i]))
|
63
|
+
end
|
64
|
+
r = " #{r.join(' | ')} ".rstrip
|
65
|
+
|
66
|
+
table << r
|
67
|
+
table << header_separator if row_i == 0 && options[:header]
|
68
|
+
end
|
69
|
+
table.join("\n") << "\n"
|
70
|
+
end
|
71
|
+
|
72
|
+
def tableize_hashes(options)
|
73
|
+
if options[:columns]
|
74
|
+
keys = options[:columns]
|
75
|
+
elsif options[:leading_columns] || options[:trailing_columns]
|
76
|
+
keys = self.first.keys.sort_by(&:to_s)
|
77
|
+
options[:leading_columns].reverse.each { |h| keys.unshift(keys.delete(h)) } if options[:leading_columns]
|
78
|
+
options[:trailing_columns].each { |h| keys.push(keys.delete(h)) } if options[:trailing_columns]
|
79
|
+
else
|
80
|
+
keys = self.first.keys.sort_by(&:to_s)
|
81
|
+
end
|
82
|
+
|
83
|
+
options = options.dup
|
84
|
+
options[:header] = true
|
85
|
+
self.collect { |h| h.values_at(*keys) }.unshift(keys).tableize(options)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
Array.send(:include, MoreCoreExtensions::ArrayTableize)
|
@@ -0,0 +1,5 @@
|
|
1
|
+
require 'more_core_extensions/core_ext/array/duplicates'
|
2
|
+
require 'more_core_extensions/core_ext/array/inclusions'
|
3
|
+
require 'more_core_extensions/core_ext/array/random'
|
4
|
+
require 'more_core_extensions/core_ext/array/stretch'
|
5
|
+
require 'more_core_extensions/core_ext/array/tableize'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'active_support/core_ext/object/blank'
|
2
|
+
|
3
|
+
module MoreCoreExtensions::HashDeletes
|
4
|
+
# Deletes all keys where the value is nil
|
5
|
+
#
|
6
|
+
# {:a => 1, :b => [], :c => nil}.delete_nils # => {:a => 1, :b => []}
|
7
|
+
def delete_nils
|
8
|
+
delete_if { |k, v| v.nil? }
|
9
|
+
end
|
10
|
+
|
11
|
+
# Deletes all keys where the value is blank
|
12
|
+
#
|
13
|
+
# {:a => 1, :b => [], :c => nil}.delete_blanks # => {:a => 1}
|
14
|
+
def delete_blanks
|
15
|
+
delete_if { |k, v| v.blank? }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
Hash.send(:include, MoreCoreExtensions::HashDeletes)
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module MoreCoreExtensions::HashNested
|
2
|
+
def fetch_path(*args)
|
3
|
+
args = args.first if args.length == 1 && args.first.kind_of?(Array)
|
4
|
+
raise ArgumentError, "must pass at least one key" if args.empty?
|
5
|
+
|
6
|
+
child = self[args.first]
|
7
|
+
return child if args.length == 1
|
8
|
+
return nil unless child.kind_of?(Hash)
|
9
|
+
return child.fetch_path(args[1..-1])
|
10
|
+
end
|
11
|
+
|
12
|
+
def has_key_path?(*args)
|
13
|
+
args = args.first if args.length == 1 && args.first.kind_of?(Array)
|
14
|
+
raise ArgumentError, "must pass at least one key" if args.empty?
|
15
|
+
|
16
|
+
key = args.first
|
17
|
+
has_child = self.has_key?(key)
|
18
|
+
return has_child if args.length == 1
|
19
|
+
|
20
|
+
child = self[key]
|
21
|
+
return false unless child.kind_of?(Hash)
|
22
|
+
return child.has_key_path?(args[1..-1])
|
23
|
+
end
|
24
|
+
alias include_path? has_key_path?
|
25
|
+
alias key_path? has_key_path?
|
26
|
+
alias member_path? has_key_path?
|
27
|
+
|
28
|
+
def store_path(*args)
|
29
|
+
raise ArgumentError, "must pass at least one key, and a value" if args.length < 2
|
30
|
+
value = args.pop
|
31
|
+
args = args.first if args.length == 1 && args.first.kind_of?(Array)
|
32
|
+
|
33
|
+
key = args.first
|
34
|
+
if args.length == 1
|
35
|
+
self[key] = value
|
36
|
+
else
|
37
|
+
child = self[key]
|
38
|
+
child = self[key] = {} unless child.kind_of?(Hash)
|
39
|
+
child.store_path(args[1..-1], value)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def delete_path(*args)
|
44
|
+
args = args.first if args.length == 1 && args.first.kind_of?(Array)
|
45
|
+
raise ArgumentError, "must pass at least one key" if args.empty?
|
46
|
+
|
47
|
+
key = args.first
|
48
|
+
if args.length == 1 || !(child = self[key]).kind_of?(Hash)
|
49
|
+
self.delete(key)
|
50
|
+
else
|
51
|
+
child.delete_path(args[1..-1])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
Hash.send(:include, MoreCoreExtensions::HashNested)
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module MoreCoreExtensions::StringFormats
|
2
|
+
# From: Regular Expression Cookbook: 4.1 Validate Email Addresses
|
3
|
+
RE_EMAIL = %r{\A[\w!#$\%&'*+/=?`\{|\}~^-]+(?:\.[\w!#$\%&'*+/=?`\{|\}~^-]+)*@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}\Z}i
|
4
|
+
def email?
|
5
|
+
!!(self =~ RE_EMAIL)
|
6
|
+
end
|
7
|
+
|
8
|
+
# From: Regular Expression Cookbook: 7.15 Validating Domain Names
|
9
|
+
RE_DOMAINNAME = %r{^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$}i
|
10
|
+
def domain_name?
|
11
|
+
!!(self =~ RE_DOMAINNAME)
|
12
|
+
end
|
13
|
+
|
14
|
+
# From: Regular Expression Cookbook: 7.16 Matching IPv4 Addresses
|
15
|
+
RE_IPV4 = %r{^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$}
|
16
|
+
def ipv4?
|
17
|
+
!!(self =~ RE_IPV4)
|
18
|
+
end
|
19
|
+
|
20
|
+
# From: Regular Expression Cookbook: 7.17 Matching IPv6 Addresses
|
21
|
+
RE_IPV6 = %r{^(?:(?:(?:[A-F0-9]{1,4}:){6}|(?=(?:[A-F0-9]{0,4}:){0,6}(?:[0-9]{1,3}\.){3}[0-9]{1,3}$)(([0-9A-F]{1,4}:){0,5}|:)((:[0-9A-F]{1,4}){1,5}:|:))(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|(?:[A-F0-9]{1,4}:){7}[A-F0-9]{1,4}|(?=(?:[A-F0-9]{0,4}:){0,7}[A-F0-9]{0,4}$)(([0-9A-F]{1,4}:){1,7}|:)((:[0-9A-F]{1,4}){1,7}|:))$}i
|
22
|
+
def ipv6?
|
23
|
+
!!(self =~ RE_IPV6)
|
24
|
+
end
|
25
|
+
|
26
|
+
def ipaddress?
|
27
|
+
ipv4? || ipv6?
|
28
|
+
end
|
29
|
+
|
30
|
+
RE_INTEGER = %r{^[0-9]+$}
|
31
|
+
def integer?
|
32
|
+
!!(self =~ RE_INTEGER)
|
33
|
+
end
|
34
|
+
|
35
|
+
RE_GUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
|
36
|
+
def guid?
|
37
|
+
!!(self =~ RE_GUID)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
String.send(:include, MoreCoreExtensions::StringFormats)
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module MoreCoreExtensions::StringHexDump
|
2
|
+
# Dumps the string in a hex editor style format. Options include:
|
3
|
+
#
|
4
|
+
# :grouping:: The number of bytes in a line. Default is 16.
|
5
|
+
# :newline:: Whether or not to add a \n after each line. Default is true.
|
6
|
+
# :start_pos:: The number at which byte counts will start. Default is 0.
|
7
|
+
# :obj:: Used in conjunction with _:meth_ to send each line to an object
|
8
|
+
# instead of returning as a string.
|
9
|
+
# :meth:: Used in conjunction with _:obj_ to send each line to an object
|
10
|
+
# instead of returning as a string.
|
11
|
+
def hex_dump(*opts)
|
12
|
+
opts = opts[0] if opts.empty? || (opts.length == 1 && opts[0].kind_of?(Hash))
|
13
|
+
raise ArgumentError, "opts must be a Hash" unless opts.nil? || opts.kind_of?(Hash)
|
14
|
+
|
15
|
+
opts = {:grouping => 16, :newline => true, :start_pos => 0}.merge!(opts || {})
|
16
|
+
obj, meth, grouping, newline, pos = opts.values_at(:obj, :meth, :grouping, :newline, :start_pos)
|
17
|
+
raise ArgumentError, "obj and meth must both be set, or both not set" if (obj.nil? && !meth.nil?) || (!obj.nil? && meth.nil?)
|
18
|
+
|
19
|
+
row_format = "0x%08x #{"%02x " * grouping} "
|
20
|
+
|
21
|
+
i = 0
|
22
|
+
last_i = self.length - 1
|
23
|
+
|
24
|
+
ret = ''
|
25
|
+
row_vals = []
|
26
|
+
row_chars = ''
|
27
|
+
|
28
|
+
self.each_byte do |c|
|
29
|
+
row_vals << c
|
30
|
+
row_chars << (c < 0x20 || (c >= 0x7F && c < 0xA0) ? '.' : c.chr)
|
31
|
+
|
32
|
+
if (i + 1) % grouping == 0 || i == last_i
|
33
|
+
row_format = "0x%08x #{"%02x " * row_vals.length}#{" " * (grouping - row_vals.length)} " if i == last_i
|
34
|
+
|
35
|
+
row_vals.unshift(pos)
|
36
|
+
ret << (row_format % row_vals) << row_chars
|
37
|
+
ret << "\n" if newline
|
38
|
+
if obj
|
39
|
+
obj.send(meth, ret)
|
40
|
+
ret.replace('')
|
41
|
+
end
|
42
|
+
|
43
|
+
pos += grouping
|
44
|
+
row_vals.clear
|
45
|
+
row_chars = ''
|
46
|
+
end
|
47
|
+
|
48
|
+
i += 1
|
49
|
+
end
|
50
|
+
|
51
|
+
return ret
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
String.send(:include, MoreCoreExtensions::StringHexDump)
|
@@ -0,0 +1 @@
|
|
1
|
+
require "more_core_extensions/version"
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'more_core_extensions/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "more_core_extensions"
|
8
|
+
spec.version = MoreCoreExtensions::VERSION
|
9
|
+
spec.authors = ["Jason Frey"]
|
10
|
+
spec.email = ["fryguy9@gmail.com"]
|
11
|
+
spec.description = %q{MoreCoreExtensions are a set of core extensions beyond those provided by ActiveSupport.}
|
12
|
+
spec.summary = spec.description
|
13
|
+
spec.homepage = "http://github.com/ManageIQ/more_core_extensions"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "coveralls"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
spec.add_development_dependency "rspec"
|
25
|
+
|
26
|
+
spec.add_dependency "activesupport"
|
27
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require_relative "../../spec_helper"
|
2
|
+
|
3
|
+
describe Array do
|
4
|
+
it '#duplicates' do
|
5
|
+
[1, 2, 3, 4].duplicates.should be_empty
|
6
|
+
[1, 2, 3, 4, 2, 4].duplicates.should match_array [2, 4]
|
7
|
+
|
8
|
+
['1', '2', '3', '4'].duplicates.should be_empty
|
9
|
+
['1', '2', '3', '4', '2', '4'].duplicates.should match_array ['2', '4']
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative "../../spec_helper"
|
2
|
+
|
3
|
+
describe Array do
|
4
|
+
it '#include_any?' do
|
5
|
+
[1, 2, 3].include_any?(1, 2).should be_true
|
6
|
+
[1, 2, 3].include_any?(1, 4).should be_true
|
7
|
+
[1, 2, 3].include_any?(4, 5).should be_false
|
8
|
+
|
9
|
+
['1', '2', '3'].include_any?('1', '2').should be_true
|
10
|
+
['1', '2', '3'].include_any?('1', '4').should be_true
|
11
|
+
['1', '2', '3'].include_any?('4', '5').should be_false
|
12
|
+
end
|
13
|
+
|
14
|
+
it '#include_none?' do
|
15
|
+
[1, 2, 3].include_none?(1, 2).should be_false
|
16
|
+
[1, 2, 3].include_none?(1, 4).should be_false
|
17
|
+
[1, 2, 3].include_none?(4, 5).should be_true
|
18
|
+
|
19
|
+
['1', '2', '3'].include_none?('1', '2').should be_false
|
20
|
+
['1', '2', '3'].include_none?('1', '4').should be_false
|
21
|
+
['1', '2', '3'].include_none?('4', '5').should be_true
|
22
|
+
end
|
23
|
+
|
24
|
+
it '#include_all?' do
|
25
|
+
[1, 2, 3].include_all?(1, 2).should be_true
|
26
|
+
[1, 2, 3].include_all?(1, 4).should be_false
|
27
|
+
[1, 2, 3].include_all?(4, 5).should be_false
|
28
|
+
|
29
|
+
['1', '2', '3'].include_all?('1', '2').should be_true
|
30
|
+
['1', '2', '3'].include_all?('1', '4').should be_false
|
31
|
+
['1', '2', '3'].include_all?('4', '5').should be_false
|
32
|
+
end
|
33
|
+
end
|