more_core_extensions 3.6.0 → 4.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/.travis.yml +5 -5
- data/CHANGELOG.md +42 -1
- data/Gemfile +10 -2
- data/README.md +22 -2
- data/bin/console +1 -1
- data/lib/more_core_extensions/all.rb +5 -0
- data/lib/more_core_extensions/core_ext/array.rb +2 -0
- data/lib/more_core_extensions/core_ext/array/compact_map.rb +19 -0
- data/lib/more_core_extensions/core_ext/array/deletes.rb +9 -0
- data/lib/more_core_extensions/core_ext/array/sorting.rb +57 -0
- data/lib/more_core_extensions/core_ext/array/tableize.rb +37 -3
- data/lib/more_core_extensions/core_ext/benchmark.rb +1 -0
- data/lib/more_core_extensions/core_ext/benchmark/realtime_store.rb +107 -0
- data/lib/more_core_extensions/core_ext/class.rb +1 -0
- data/lib/more_core_extensions/core_ext/class/hierarchy.rb +55 -0
- data/lib/more_core_extensions/core_ext/digest.rb +1 -0
- data/lib/more_core_extensions/core_ext/digest/uuid.rb +26 -0
- data/lib/more_core_extensions/core_ext/hash/deletes.rb +10 -0
- data/lib/more_core_extensions/core_ext/math.rb +1 -0
- data/lib/more_core_extensions/core_ext/math/slope.rb +54 -0
- data/lib/more_core_extensions/core_ext/object.rb +0 -1
- data/lib/more_core_extensions/core_ext/process.rb +1 -0
- data/lib/more_core_extensions/core_ext/process/pause_resume.rb +110 -0
- data/lib/more_core_extensions/core_ext/shared/nested.rb +15 -0
- data/lib/more_core_extensions/version.rb +1 -1
- data/more_core_extensions.gemspec +2 -1
- metadata +33 -9
- data/lib/more_core_extensions/core_ext/object/descendants.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d8d52470776addb4edcca50184d26029d46a6a513cbc51125d539816974c2758
|
4
|
+
data.tar.gz: a0bbdb4f9f454eef6881cc85babc15523dcab44c1d5516f67aeae0037b69491b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f1bc6f58dffd72b60a0746ad568bf9b7a4dbc0c7e0b742f9546ea10b75a54f9a098938726cde53fcfcec1a810b173d20d164ee15c0d570cac2033a785c702ca1
|
7
|
+
data.tar.gz: b301d6ed331a268b9ecf6d5e7b8ea0afdfb4b2a6333dc1eb8886e5a496be807bdc43a9c9335e6f514ac32ba3717bc8e8068cc4cf4feecd007ed8a77f21d27677
|
data/.travis.yml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
- "2.0"
|
4
3
|
- "2.1"
|
5
4
|
- "2.2"
|
6
|
-
- "2.3
|
7
|
-
- "2.4
|
5
|
+
- "2.3"
|
6
|
+
- "2.4"
|
7
|
+
- "2.5.8"
|
8
|
+
- "2.6.6"
|
9
|
+
- "2.7.1"
|
8
10
|
- ruby-head
|
9
11
|
- jruby-head
|
10
|
-
sudo: false
|
11
12
|
cache: bundler
|
12
|
-
before_install: gem install bundler -v ">= 1.13.6"
|
13
13
|
after_script: bundle exec codeclimate-test-reporter
|
14
14
|
matrix:
|
15
15
|
allow_failures:
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,42 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
4
4
|
|
5
5
|
## [Unreleased]
|
6
6
|
|
7
|
+
## [4.2.0] - 2020-07-20
|
8
|
+
### Added
|
9
|
+
- Add bundler-inject allowing developers to override dependencies [[#89](https://github.com/ManageIQ/more_core_extensions/pull/89)]
|
10
|
+
- Add Array and Hash #deep_clone and #deep_delete [[#91](https://github.com/ManageIQ/more_core_extensions/pull/91)]
|
11
|
+
- Add Digest::UUID.clean to properly format UUID strings [[#81](https://github.com/ManageIQ/more_core_extensions/pull/81)]
|
12
|
+
|
13
|
+
###Changed
|
14
|
+
- Update ArrayTableize to properly set field width for color text [[#87](https://github.com/ManageIQ/more_core_extensions/pull/87)]
|
15
|
+
- Change Array#format_table header output to markdown vs postgres [[#83](https://github.com/ManageIQ/more_core_extensions/pull/83)]
|
16
|
+
|
17
|
+
## [4.1.0] - 2020-04-30
|
18
|
+
### Added
|
19
|
+
- Added Ruby 2.7 support [[#79](https://github.com/ManageIQ/more_core_extensions/pull/79)]
|
20
|
+
- Added Process#pause, Process#resume, and Process#alive? [[#73](https://github.com/ManageIQ/more_core_extensions/pull/73)]
|
21
|
+
|
22
|
+
## [4.0.0] - 2020-01-31
|
23
|
+
### Changed
|
24
|
+
- **BREAKING**: Moved Object#descendant_get to Class#descendant_get [[#75](https://github.com/ManageIQ/more_core_extensions/pull/75)]
|
25
|
+
- **BREAKING**: Removed deprecated Enumerable#stable_sort_by [[#76](https://github.com/ManageIQ/more_core_extensions/pull/76)]
|
26
|
+
|
27
|
+
## [3.8.0] - 2020-01-31
|
28
|
+
### Changed
|
29
|
+
- Renamed Enumerable#stable_sort_by to Array#tabular_sort [[#68](https://github.com/ManageIQ/more_core_extensions/pull/68)]
|
30
|
+
- Deprecated Enumerable#stable_sort_by [[#74](https://github.com/ManageIQ/more_core_extensions/pull/74)]
|
31
|
+
|
32
|
+
### Added
|
33
|
+
- Added Class#leaf_subclasses [[#71](https://github.com/ManageIQ/more_core_extensions/pull/71)]
|
34
|
+
- Added Array#compact_map [[#63](https://github.com/ManageIQ/more_core_extensions/pull/63)]
|
35
|
+
|
36
|
+
## [3.7.0] - 2019-02-04
|
37
|
+
### Added
|
38
|
+
- Added Enumerable#stable_sort_by [[#67](https://github.com/ManageIQ/more_core_extensions/pull/67)]
|
39
|
+
- Added Math#slope_y_intercept, #slope_x_intercept, #linear_regression [[#50](https://github.com/ManageIQ/more_core_extensions/pull/50)]
|
40
|
+
- Added Benchmark#realtime_store, #realtime_block and helper methods [[#65](https://github.com/ManageIQ/more_core_extensions/pull/65)]
|
41
|
+
- Added Class#hierarchy and #lineage [[#61](https://github.com/ManageIQ/more_core_extensions/pull/61)]
|
42
|
+
|
7
43
|
## [3.6.0] - 2018-03-01
|
8
44
|
### Added
|
9
45
|
- Added String#decimal_si_to_big_decimal [[#59](https://github.com/ManageIQ/more_core_extensions/pull/59)]
|
@@ -61,7 +97,12 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
61
97
|
- Upgraded to RSpec 3 [[#16](https://github.com/ManageIQ/more_core_extensions/pull/16)]
|
62
98
|
- Added the Change Log!
|
63
99
|
|
64
|
-
[Unreleased]: https://github.com/ManageIQ/more_core_extensions/compare/
|
100
|
+
[Unreleased]: https://github.com/ManageIQ/more_core_extensions/compare/v4.2.0...HEAD
|
101
|
+
[4.2.0]: https://github.com/ManageIQ/more_core_extensions/compare/v4.1.0...v4.2.0
|
102
|
+
[4.1.0]: https://github.com/ManageIQ/more_core_extensions/compare/v4.0.0...v4.1.0
|
103
|
+
[4.0.0]: https://github.com/ManageIQ/more_core_extensions/compare/v3.8.0...v4.0.0
|
104
|
+
[3.8.0]: https://github.com/ManageIQ/more_core_extensions/compare/v3.7.0...v3.8.0
|
105
|
+
[3.7.0]: https://github.com/ManageIQ/more_core_extensions/compare/v3.6.0...v3.7.0
|
65
106
|
[3.6.0]: https://github.com/ManageIQ/more_core_extensions/compare/v3.5.0...v3.6.0
|
66
107
|
[3.5.0]: https://github.com/ManageIQ/more_core_extensions/compare/v3.4.0...v3.5.0
|
67
108
|
[3.4.0]: https://github.com/ManageIQ/more_core_extensions/compare/v3.3.0...v3.4.0
|
data/Gemfile
CHANGED
@@ -1,8 +1,16 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
|
3
|
+
plugin 'bundler-inject'
|
4
|
+
require File.join(Bundler::Plugin.index.load_paths("bundler-inject")[0], "bundler-inject") rescue nil
|
5
|
+
|
3
6
|
# Specify your gem's dependencies in more_core_extensions.gemspec
|
4
7
|
gemspec
|
5
8
|
|
6
|
-
#
|
7
|
-
|
9
|
+
# Rails 5 dropped support for Ruby < 2.2.2
|
10
|
+
# Rails 6 dropped support for Ruby < 2.4.4
|
11
|
+
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.2.2")
|
12
|
+
active_support_version = "< 5"
|
13
|
+
elsif Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.4.4")
|
14
|
+
active_support_version = "< 6"
|
15
|
+
end
|
8
16
|
gem 'activesupport', active_support_version
|
data/README.md
CHANGED
@@ -14,9 +14,12 @@ MoreCoreExtensions are a set of core extensions beyond those provided by ActiveS
|
|
14
14
|
|
15
15
|
#### Array
|
16
16
|
|
17
|
+
* core_ext/array/compact_map.rb
|
18
|
+
* `#compact_map` - Collect non-nil results from the block
|
17
19
|
* core_ext/array/deletes.rb
|
18
20
|
* `#delete_blanks` - Deletes all items where the value is blank
|
19
21
|
* `#delete_nils` - Deletes all items where the value is nil
|
22
|
+
* `#deep_delete` - Deletes nested hash key elements
|
20
23
|
* core_ext/array/duplicates.rb
|
21
24
|
* `#duplicates` - Returns an Array of the duplicates found
|
22
25
|
* core_ext/array/element_counts.rb
|
@@ -35,6 +38,8 @@ MoreCoreExtensions are a set of core extensions beyond those provided by ActiveS
|
|
35
38
|
* core_ext/array/random.rb
|
36
39
|
* `#random_index` - Picks a valid index randomly
|
37
40
|
* `#random_element` - Picks an element randomly
|
41
|
+
* core_ext/array/sorting.rb
|
42
|
+
* `#tabular_sort` - Sorts an Array of Hashes by specific columns
|
38
43
|
* core_ext/array/stretch.rb
|
39
44
|
* `.stretch` - Stretch all argument Arrays to make them the same size
|
40
45
|
* `.stretch!` - Stretch all argument Arrays to make them the same size. Modifies the arguments in place.
|
@@ -44,11 +49,20 @@ MoreCoreExtensions are a set of core extensions beyond those provided by ActiveS
|
|
44
49
|
* core_ext/array/tableize.rb
|
45
50
|
* `#tableize` - Create a string representation of receiver in a tabular format if receiver is an Array of Arrays or an Array of Hashes
|
46
51
|
|
52
|
+
#### Class
|
53
|
+
|
54
|
+
* core_ext/class/hierarchy.rb
|
55
|
+
* `#descendant_get` - Returns the descendant with a given name
|
56
|
+
* `#hierarchy` - Returns a tree-like Hash structure of all descendants.
|
57
|
+
* `#lineage` - Returns an Array of all superclasses.
|
58
|
+
* `#leaf_subclasses` - Returns an Array of all descendants which have no subclasses.
|
59
|
+
|
47
60
|
#### Hash
|
48
61
|
|
49
62
|
* core_ext/hash/deletes.rb
|
50
63
|
* `#delete_blanks` - Deletes all keys where the value is blank
|
51
64
|
* `#delete_nils` - Deletes all keys where the value is nil
|
65
|
+
* `#deep_delete` - Deletes nested hash key elements
|
52
66
|
* core_ext/hash/nested.rb (see [Shared](#shared))
|
53
67
|
* `#delete_blank_paths` - Deletes all paths where the value is blank
|
54
68
|
* core_ext/hash/sorting.rb (see [Shared](#shared))
|
@@ -75,11 +89,16 @@ MoreCoreExtensions are a set of core extensions beyond those provided by ActiveS
|
|
75
89
|
|
76
90
|
#### Object
|
77
91
|
|
78
|
-
* core_ext/module/descendants.rb
|
79
|
-
* `#descendant_get` - Returns the descendant with a given name
|
80
92
|
* core_ext/module/namespace.rb
|
81
93
|
* `#in_namespace?` - Returns whether or not the object is in the given namespace
|
82
94
|
|
95
|
+
#### Process
|
96
|
+
|
97
|
+
* core_ext/process/pause_resume.rb
|
98
|
+
* `.pause` - Pauses a process
|
99
|
+
* `.resume` - Resumes a paused process
|
100
|
+
* `.alive?` - Returns whether or not a process is running
|
101
|
+
|
83
102
|
#### Range
|
84
103
|
|
85
104
|
* core_ext/range/step_value.rb
|
@@ -112,6 +131,7 @@ MoreCoreExtensions are a set of core extensions beyond those provided by ActiveS
|
|
112
131
|
#### Shared
|
113
132
|
|
114
133
|
* core_ext/shared/nested.rb
|
134
|
+
* `#deep_clone` - Performs a Marshal based deep clone
|
115
135
|
* `#delete_path` - Delete the value at the specified nesting
|
116
136
|
* `#fetch_path` - Fetch the value at the specified nesting
|
117
137
|
* `#find_path` - Detect which nesting holds the specified value
|
data/bin/console
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require "bundler/setup"
|
4
|
-
require "more_core_extensions"
|
4
|
+
require "more_core_extensions/all"
|
5
5
|
|
6
6
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
7
|
# with your gem easier. You can also use a different console, if you like.
|
@@ -1,10 +1,15 @@
|
|
1
1
|
require 'more_core_extensions/version'
|
2
2
|
|
3
3
|
require 'more_core_extensions/core_ext/array'
|
4
|
+
require 'more_core_extensions/core_ext/benchmark'
|
5
|
+
require 'more_core_extensions/core_ext/class'
|
6
|
+
require 'more_core_extensions/core_ext/digest'
|
4
7
|
require 'more_core_extensions/core_ext/hash'
|
8
|
+
require 'more_core_extensions/core_ext/math'
|
5
9
|
require 'more_core_extensions/core_ext/module'
|
6
10
|
require 'more_core_extensions/core_ext/numeric'
|
7
11
|
require 'more_core_extensions/core_ext/object'
|
12
|
+
require 'more_core_extensions/core_ext/process'
|
8
13
|
require 'more_core_extensions/core_ext/range'
|
9
14
|
require 'more_core_extensions/core_ext/string'
|
10
15
|
require 'more_core_extensions/core_ext/symbol'
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'more_core_extensions/core_ext/array/compact_map'
|
1
2
|
require 'more_core_extensions/core_ext/array/deletes'
|
2
3
|
require 'more_core_extensions/core_ext/array/duplicates'
|
3
4
|
require 'more_core_extensions/core_ext/array/element_counts'
|
@@ -5,5 +6,6 @@ require 'more_core_extensions/core_ext/array/inclusions'
|
|
5
6
|
require 'more_core_extensions/core_ext/array/math'
|
6
7
|
require 'more_core_extensions/core_ext/array/nested'
|
7
8
|
require 'more_core_extensions/core_ext/array/random'
|
9
|
+
require 'more_core_extensions/core_ext/array/sorting'
|
8
10
|
require 'more_core_extensions/core_ext/array/stretch'
|
9
11
|
require 'more_core_extensions/core_ext/array/tableize'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module MoreCoreExtensions
|
2
|
+
module ArrayCompactMap
|
3
|
+
# Collect non-nil results from the block. Basically [].collect { |i| ... }.compact
|
4
|
+
#
|
5
|
+
# [1,2,3,4,5].compact_map { |i| i * 2 if i.odd?} # => [2,6,10]
|
6
|
+
def compact_map
|
7
|
+
return enum_for(:compact_map) unless block_given?
|
8
|
+
|
9
|
+
[].tap do |results|
|
10
|
+
each do |i|
|
11
|
+
result = yield(i)
|
12
|
+
results << result if result
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
Array.send(:include, MoreCoreExtensions::ArrayCompactMap)
|
@@ -15,6 +15,15 @@ module MoreCoreExtensions
|
|
15
15
|
def delete_blanks
|
16
16
|
delete_if { |i| i.blank? }
|
17
17
|
end
|
18
|
+
|
19
|
+
# Deletes all keys and subkeys that match +key+.
|
20
|
+
#
|
21
|
+
# [{:a => {:b => 2, :c => 3}}].deep_delete(:b) # => [{:a => {:c => 3}}]
|
22
|
+
#
|
23
|
+
def deep_delete(key)
|
24
|
+
each { |i| i.deep_delete(key) if i.respond_to?(:deep_delete) }
|
25
|
+
self
|
26
|
+
end
|
18
27
|
end
|
19
28
|
end
|
20
29
|
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module MoreCoreExtensions
|
2
|
+
module StableSorting
|
3
|
+
# Sorts an Array of Hashes by specific columns.
|
4
|
+
#
|
5
|
+
# Rows are sorted by +col_names+, if given, otherwise by the given block.
|
6
|
+
# The +order+ parameter can be given :ascending or :descending and
|
7
|
+
# defaults to :ascending.
|
8
|
+
#
|
9
|
+
# Note:
|
10
|
+
# - Strings are sorted case-insensitively
|
11
|
+
# - nil values are sorted last
|
12
|
+
# - Boolean values are sorted alphabetically (i.e. false then true)
|
13
|
+
#
|
14
|
+
# [
|
15
|
+
# {:col1 => 'b', :col2 => 2},
|
16
|
+
# {:col1 => 'b', :col2 => 1},
|
17
|
+
# {:col1 => 'A', :col2 => 1}
|
18
|
+
# ].tabular_sort([:col1, :col2])
|
19
|
+
#
|
20
|
+
# # => [
|
21
|
+
# # {:col1 => 'A', :col2 => 1},
|
22
|
+
# # {:col1 => 'b', :col2 => 1},
|
23
|
+
# # {:col1 => 'b', :col2 => 2}
|
24
|
+
# # ]
|
25
|
+
def tabular_sort(col_names = nil, order = nil, &block)
|
26
|
+
# stabilizer is needed because of
|
27
|
+
# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/170565
|
28
|
+
stabilizer = 0
|
29
|
+
nil_rows, sortable =
|
30
|
+
partition do |r|
|
31
|
+
Array(col_names).any? { |c| r[c].nil? }
|
32
|
+
end
|
33
|
+
|
34
|
+
data_array =
|
35
|
+
if col_names
|
36
|
+
sortable.sort_by do |r|
|
37
|
+
stabilizer += 1
|
38
|
+
[Array(col_names).map do |col|
|
39
|
+
val = r[col]
|
40
|
+
val = val.downcase if val.kind_of?(String)
|
41
|
+
val = val.to_s if val.kind_of?(FalseClass) || val.kind_of?(TrueClass)
|
42
|
+
val
|
43
|
+
end, stabilizer]
|
44
|
+
end
|
45
|
+
else
|
46
|
+
sortable.sort_by(&block)
|
47
|
+
end.to_a
|
48
|
+
|
49
|
+
data_array += nil_rows
|
50
|
+
|
51
|
+
data_array.reverse! if order == :descending
|
52
|
+
data_array
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
Array.send(:include, MoreCoreExtensions::StableSorting)
|
@@ -53,6 +53,9 @@ module MoreCoreExtensions
|
|
53
53
|
|
54
54
|
private
|
55
55
|
|
56
|
+
ANSI_ESCAPE_SEQUENCE = /\e\[[^m]+m/.freeze
|
57
|
+
ANSI_RESET = "\e[0m".freeze
|
58
|
+
|
56
59
|
def tableize_hashes
|
57
60
|
# Convert the target to an Array of Arrays
|
58
61
|
keys = options[:columns] || columns_from_hash_keys
|
@@ -102,7 +105,7 @@ module MoreCoreExtensions
|
|
102
105
|
end
|
103
106
|
|
104
107
|
def apply_width!(widths, field, field_i)
|
105
|
-
widths[field_i] = [widths[field_i].to_i, field.to_s.length].max
|
108
|
+
widths[field_i] = [widths[field_i].to_i, ansi_strip(field.to_s).length].max
|
106
109
|
widths[field_i] = [options[:max_width], widths[field_i].to_i].min if options[:max_width]
|
107
110
|
end
|
108
111
|
|
@@ -118,13 +121,44 @@ module MoreCoreExtensions
|
|
118
121
|
end
|
119
122
|
|
120
123
|
def format_field(field, width, justification)
|
121
|
-
field = field.to_s.gsub(/\n|\r/, '')
|
124
|
+
field = field.to_s.gsub(/\n|\r/, '')
|
125
|
+
field = ansi_truncate(field, width)
|
122
126
|
"%0#{justification}#{width}s" % field
|
123
127
|
end
|
124
128
|
|
129
|
+
def ansi_escapes?(field)
|
130
|
+
!!field.match(ANSI_ESCAPE_SEQUENCE)
|
131
|
+
end
|
132
|
+
|
133
|
+
def ansi_escapes(field)
|
134
|
+
field.to_enum(:scan, ANSI_ESCAPE_SEQUENCE).map { Regexp.last_match }
|
135
|
+
end
|
136
|
+
|
137
|
+
def ansi_strip(field)
|
138
|
+
field.gsub(ANSI_ESCAPE_SEQUENCE, '')
|
139
|
+
end
|
140
|
+
|
141
|
+
def ansi_truncate(field, width)
|
142
|
+
escapes = ansi_escapes(field)
|
143
|
+
if escapes.none?
|
144
|
+
field.slice(0, width)
|
145
|
+
else
|
146
|
+
escape_widths = 0
|
147
|
+
escapes.each do |e|
|
148
|
+
break if e.offset(0).first - escape_widths >= width
|
149
|
+
|
150
|
+
escape_widths += e[0].size
|
151
|
+
end
|
152
|
+
|
153
|
+
field = field.slice(0, width + escape_widths)
|
154
|
+
field << ANSI_RESET if ansi_escapes?(field) && !field.end_with?(ANSI_RESET)
|
155
|
+
field
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
125
159
|
def format_table(table, widths)
|
126
160
|
if options[:header] && table.size > 1
|
127
|
-
header_separator = widths.collect { |w| "-" * (w + 2) }.join("
|
161
|
+
header_separator = widths.collect { |w| "-" * (w + 2) }.join("|")
|
128
162
|
table.insert(1, header_separator)
|
129
163
|
end
|
130
164
|
table.join("\n") << "\n"
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'more_core_extensions/core_ext/benchmark/realtime_store'
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
|
3
|
+
module MoreCoreExtensions
|
4
|
+
module BenchmarkRealtimeStore
|
5
|
+
# Stores the elapsed real time used to execute the given block in the given
|
6
|
+
# hash for the given key and returns the result from the block. If the hash
|
7
|
+
# already has a value for that key, the time is accumulated.
|
8
|
+
#
|
9
|
+
# timings = {}
|
10
|
+
#
|
11
|
+
# Benchmark.realtime_store(timings, :sleep) { sleep 2; "foo" } # => "foo"
|
12
|
+
# timings # => {:sleep => 2.00}
|
13
|
+
#
|
14
|
+
# Benchmark.realtime_store(timings, :sleep) { sleep 2; "bar" } # => "bar"
|
15
|
+
# timings # => {:sleep => 4.00}
|
16
|
+
def realtime_store(hash, key)
|
17
|
+
ret = nil
|
18
|
+
r0 = Time.now
|
19
|
+
begin
|
20
|
+
ret = yield
|
21
|
+
ensure
|
22
|
+
r1 = Time.now
|
23
|
+
hash[key] = (hash[key] || 0) + (r1.to_f - r0.to_f)
|
24
|
+
end
|
25
|
+
ret
|
26
|
+
end
|
27
|
+
|
28
|
+
# Stores the elapsed real time used to execute the given block for the given
|
29
|
+
# key and returns the hash as well as the result from the block. The hash is
|
30
|
+
# stored globally, keyed on thread id, and is cleared once the topmost nested
|
31
|
+
# call completes. If the hash already has a value for that key, the time is
|
32
|
+
# accumulated.
|
33
|
+
#
|
34
|
+
# Benchmark.realtime_block(:sleep) do
|
35
|
+
# sleep 2
|
36
|
+
# "foo"
|
37
|
+
# end # => ["foo", {:sleep => 2.00}]
|
38
|
+
#
|
39
|
+
# Benchmark.realtime_block(:outer_sleep) do
|
40
|
+
# sleep 2
|
41
|
+
# Benchmark.realtime_block(:inner_sleep) { sleep 2 }
|
42
|
+
# "bar"
|
43
|
+
# end # => ["bar", {:inner_sleep => 2.00, :outer_sleep => 4.00}]
|
44
|
+
#
|
45
|
+
# Benchmark.realtime_block(:outer_sleep) do
|
46
|
+
# sleep 2
|
47
|
+
# 2.times do
|
48
|
+
# Benchmark.realtime_block(:inner_sleep) { sleep 2 }
|
49
|
+
# end
|
50
|
+
# "baz"
|
51
|
+
# end # => ["baz", {:inner_sleep => 4.00, :outer_sleep => 6.00}]
|
52
|
+
def realtime_block(key, &block)
|
53
|
+
hash = current_realtime
|
54
|
+
|
55
|
+
if in_realtime_block?
|
56
|
+
ret = realtime_store(hash, key, &block)
|
57
|
+
return ret, hash
|
58
|
+
else
|
59
|
+
begin
|
60
|
+
self.current_realtime = hash
|
61
|
+
begin
|
62
|
+
ret = realtime_store(hash, key, &block)
|
63
|
+
return ret, hash
|
64
|
+
rescue Exception => err # rubocop:disable Lint/RescueException
|
65
|
+
err.define_singleton_method(:timings) { hash } unless err.respond_to?(:timings)
|
66
|
+
raise
|
67
|
+
ensure
|
68
|
+
delete_current_realtime
|
69
|
+
end
|
70
|
+
ensure
|
71
|
+
# A second layer of protection in case Timeout::Error struck right after
|
72
|
+
# setting self.current_realtime, or right before `delete_current_realtime`.
|
73
|
+
# In those cases, current_realtime might (wrongly) still exist.
|
74
|
+
delete_current_realtime if in_realtime_block?
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def in_realtime_block?
|
80
|
+
@@realtime_by_tid.key?(thread_unique_identifier)
|
81
|
+
end
|
82
|
+
|
83
|
+
def current_realtime
|
84
|
+
@@realtime_by_tid[thread_unique_identifier] || Hash.new(0)
|
85
|
+
end
|
86
|
+
|
87
|
+
def current_realtime=(hash)
|
88
|
+
@@realtime_by_tid[thread_unique_identifier] = hash
|
89
|
+
end
|
90
|
+
|
91
|
+
def delete_current_realtime
|
92
|
+
@@realtime_by_tid.delete(thread_unique_identifier)
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def thread_unique_identifier
|
98
|
+
# Forks inherit the @@realtime_by_tid and parent/child Thread.current.object_id
|
99
|
+
# are equal, so we need to index into the hash with the pid too.
|
100
|
+
"#{Process.pid}-#{Thread.current.object_id}"
|
101
|
+
end
|
102
|
+
|
103
|
+
@@realtime_by_tid = {}
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
Benchmark.send(:extend, MoreCoreExtensions::BenchmarkRealtimeStore)
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'more_core_extensions/core_ext/class/hierarchy'
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'active_support/core_ext/class/subclasses'
|
2
|
+
require 'active_support/core_ext/object/try'
|
3
|
+
|
4
|
+
module MoreCoreExtensions
|
5
|
+
module ClassHierarchy
|
6
|
+
# Returns the descendant with a given name
|
7
|
+
#
|
8
|
+
# require 'socket'
|
9
|
+
# IO.descendant_get("IO")
|
10
|
+
# # => IO
|
11
|
+
# IO.descendant_get("BasicSocket")
|
12
|
+
# # => BasicSocket
|
13
|
+
# IO.descendant_get("IPSocket")
|
14
|
+
# # => IPSocket
|
15
|
+
def descendant_get(desc_name)
|
16
|
+
return self if desc_name == name || desc_name.nil?
|
17
|
+
klass = descendants.find { |desc| desc.name == desc_name }
|
18
|
+
raise ArgumentError, "#{desc_name} is not a descendant of #{name}" unless klass
|
19
|
+
klass
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns a tree-like Hash structure of all descendants.
|
23
|
+
#
|
24
|
+
# require 'socket'
|
25
|
+
# IO.hierarchy
|
26
|
+
# # => {BasicSocket=>
|
27
|
+
# # {Socket=>{},
|
28
|
+
# # IPSocket=>{TCPSocket=>{TCPServer=>{}}, UDPSocket=>{}},
|
29
|
+
# # UNIXSocket=>{UNIXServer=>{}}},
|
30
|
+
# # File=>{}}
|
31
|
+
def hierarchy
|
32
|
+
subclasses.each_with_object({}) { |k, h| h[k] = k.hierarchy }
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns an Array of all superclasses.
|
36
|
+
#
|
37
|
+
# require 'socket'
|
38
|
+
# TCPServer.lineage
|
39
|
+
# # => [TCPSocket, IPSocket, BasicSocket, IO, Object, BasicObject]
|
40
|
+
def lineage
|
41
|
+
superclass.nil? ? [] : superclass.lineage.unshift(superclass)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns an Array of all descendants which have no subclasses
|
45
|
+
#
|
46
|
+
# require 'socket'
|
47
|
+
# BasicSocket.leaf_subclasses
|
48
|
+
# # => [Socket, TCPServer, UDPSocket, UNIXServer]
|
49
|
+
def leaf_subclasses
|
50
|
+
descendants.select { |d| d.subclasses.empty? }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
Class.send(:include, MoreCoreExtensions::ClassHierarchy)
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'more_core_extensions/core_ext/digest/uuid'
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'active_support/core_ext/digest/uuid'
|
2
|
+
|
3
|
+
module Digest
|
4
|
+
module UUID
|
5
|
+
UUID_REGEX_FORMAT = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.freeze
|
6
|
+
|
7
|
+
# Takes a UUID string of varying formats and cleans it. It will strip invalid characters,
|
8
|
+
# such as leading and trailing brackets as well as whitespace. The result is a lowercased,
|
9
|
+
# canonical UUID string.
|
10
|
+
#
|
11
|
+
# If the +guid+ argument is nil or blank, then nil is returned. If the +guid+ is already
|
12
|
+
# clean, then no additional cleaning occurs, and it is returned as-is.
|
13
|
+
#
|
14
|
+
# @param guid [String] A string that should more or less represent a UUID.
|
15
|
+
# @return [String] A lowercase v4 UUID string stripped of any extraneous characters.
|
16
|
+
#
|
17
|
+
def self.clean(guid)
|
18
|
+
return nil if guid.nil?
|
19
|
+
g = guid.to_s.downcase
|
20
|
+
return nil if g.strip.empty?
|
21
|
+
return g if g.length == 36 && g =~ UUID_REGEX_FORMAT
|
22
|
+
g.delete!('^0-9a-f')
|
23
|
+
g.sub!(/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/, '\1-\2-\3-\4-\5')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -15,6 +15,16 @@ module MoreCoreExtensions
|
|
15
15
|
def delete_blanks
|
16
16
|
delete_if { |k, v| v.blank? }
|
17
17
|
end
|
18
|
+
|
19
|
+
# Deletes all keys and subkeys that match +key+.
|
20
|
+
#
|
21
|
+
# {:a => {:b => 2, :c => 3}}.deep_delete(:b) # => {:a => {:c => 3}}
|
22
|
+
#
|
23
|
+
def deep_delete(key)
|
24
|
+
key = [key] unless key.kind_of?(Array)
|
25
|
+
key.each { |k| delete(k) }
|
26
|
+
each_value { |v| v.deep_delete(key) if v.respond_to?(:deep_delete) }
|
27
|
+
end
|
18
28
|
end
|
19
29
|
end
|
20
30
|
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'more_core_extensions/core_ext/math/slope'
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'more_core_extensions/core_ext/numeric/math'
|
2
|
+
|
3
|
+
module MoreCoreExtensions
|
4
|
+
module MathSlope
|
5
|
+
module ClassMethods
|
6
|
+
# Finds the y coordinate given x, slope of the line and the y intercept
|
7
|
+
#
|
8
|
+
# `y = mx + b`
|
9
|
+
# Where `m` is the slope of the line and `b` is the y intercept
|
10
|
+
#
|
11
|
+
# Math.slope_y_intercept(1, 0.5, 1) # => 1.5
|
12
|
+
def slope_y_intercept(x, slope, y_intercept)
|
13
|
+
slope * x + y_intercept
|
14
|
+
end
|
15
|
+
|
16
|
+
# Finds the x coordinate given y, slope of the line and the y intercept
|
17
|
+
#
|
18
|
+
# `x = (y - b) / m`
|
19
|
+
# Where `m` is the slope of the line and `b` is the y intercept
|
20
|
+
#
|
21
|
+
# Math.slope_x_intercept(1.5, 0.5, 1) # => 1.0
|
22
|
+
def slope_x_intercept(y, slope, y_intercept)
|
23
|
+
(y - y_intercept) / slope.to_f
|
24
|
+
end
|
25
|
+
|
26
|
+
# Finds the linear regression of the given coordinates. Coordinates should be given as x, y pairs.
|
27
|
+
#
|
28
|
+
# Returns the slope of the line, the y intercept, and the R-squared value.
|
29
|
+
#
|
30
|
+
# Math.linear_regression([1.0, 1.0], [2.0, 2.0]) # => [1.0, 0.0, 1.0]
|
31
|
+
def linear_regression(*coordinates)
|
32
|
+
return if coordinates.empty?
|
33
|
+
|
34
|
+
x_array, y_array = coordinates.transpose
|
35
|
+
sum_x = x_array.sum
|
36
|
+
sum_x2 = x_array.map(&:square).sum
|
37
|
+
sum_y = y_array.sum
|
38
|
+
sum_y2 = y_array.map(&:square).sum
|
39
|
+
sum_xy = coordinates.map { |x, y| x * y }.sum
|
40
|
+
|
41
|
+
n = coordinates.size.to_f
|
42
|
+
slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x.square)
|
43
|
+
return if slope.nan?
|
44
|
+
|
45
|
+
y_intercept = (sum_y - slope * sum_x) / n
|
46
|
+
r_squared = (n * sum_xy - sum_x * sum_y) / Math.sqrt((n * sum_x2 - sum_x.square) * (n * sum_y2 - sum_y.square)) rescue nil
|
47
|
+
|
48
|
+
return slope, y_intercept, r_squared
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
Math.send(:extend, MoreCoreExtensions::MathSlope::ClassMethods)
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'more_core_extensions/core_ext/process/pause_resume'
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module MoreCoreExtensions
|
2
|
+
module ProcessPauseResume
|
3
|
+
if Gem.win_platform?
|
4
|
+
require 'fiddle'
|
5
|
+
ntdll = Fiddle.dlopen('ntdll')
|
6
|
+
kernel32 = Fiddle.dlopen('kernel32')
|
7
|
+
|
8
|
+
NtSuspendProcess = Fiddle::Function.new(
|
9
|
+
ntdll['NtSuspendProcess'],
|
10
|
+
[Fiddle::TYPE_UINTPTR_T],
|
11
|
+
Fiddle::TYPE_INT
|
12
|
+
)
|
13
|
+
|
14
|
+
private_constant :NtSuspendProcess
|
15
|
+
|
16
|
+
NtResumeProcess = Fiddle::Function.new(
|
17
|
+
ntdll['NtResumeProcess'],
|
18
|
+
[Fiddle::TYPE_UINTPTR_T],
|
19
|
+
Fiddle::TYPE_INT
|
20
|
+
)
|
21
|
+
|
22
|
+
private_constant :NtResumeProcess
|
23
|
+
|
24
|
+
OpenProcess = Fiddle::Function.new(
|
25
|
+
kernel32['OpenProcess'],
|
26
|
+
[Fiddle::TYPE_LONG, Fiddle::TYPE_INT, Fiddle::TYPE_LONG],
|
27
|
+
Fiddle::TYPE_UINTPTR_T
|
28
|
+
)
|
29
|
+
|
30
|
+
private_constant :OpenProcess
|
31
|
+
|
32
|
+
CloseHandle = Fiddle::Function.new(
|
33
|
+
kernel32['CloseHandle'],
|
34
|
+
[Fiddle::TYPE_UINTPTR_T],
|
35
|
+
Fiddle::TYPE_INT
|
36
|
+
)
|
37
|
+
|
38
|
+
private_constant :CloseHandle
|
39
|
+
|
40
|
+
PROCESS_SUSPEND_RESUME = 0x00000800
|
41
|
+
|
42
|
+
private_constant :PROCESS_SUSPEND_RESUME
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns whether or not the given process is running.
|
46
|
+
#
|
47
|
+
def alive?(pid)
|
48
|
+
Process.kill(0, pid)
|
49
|
+
true
|
50
|
+
rescue Errno::ESRCH
|
51
|
+
false
|
52
|
+
end
|
53
|
+
|
54
|
+
# Suspend the process +pid+. If the process isn't running then this is no-op.
|
55
|
+
#
|
56
|
+
if Gem.win_platform?
|
57
|
+
def pause(pid)
|
58
|
+
return unless alive?(pid)
|
59
|
+
|
60
|
+
begin
|
61
|
+
handle = OpenProcess.call(PROCESS_SUSPEND_RESUME, 0, pid)
|
62
|
+
|
63
|
+
if handle == 0
|
64
|
+
raise SystemCallError, Fiddle.win32_last_error, "OpenProcess"
|
65
|
+
end
|
66
|
+
|
67
|
+
if NtSuspendProcess.call(handle) != 0
|
68
|
+
raise SystemCallError, Fiddle.win32_last_error, "NtSuspendProcess"
|
69
|
+
end
|
70
|
+
ensure
|
71
|
+
CloseHandle.call(handle) if handle
|
72
|
+
end
|
73
|
+
1 # For cross-platform compatibility
|
74
|
+
end
|
75
|
+
else
|
76
|
+
def pause(pid)
|
77
|
+
Process.kill('STOP', pid) if alive?(pid)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Resume the process +pid+. If the process isn't running then this is a no-op.
|
82
|
+
#
|
83
|
+
if Gem.win_platform?
|
84
|
+
def resume(pid)
|
85
|
+
return unless alive?(pid)
|
86
|
+
|
87
|
+
begin
|
88
|
+
handle = OpenProcess.call(PROCESS_SUSPEND_RESUME, 0, pid)
|
89
|
+
|
90
|
+
if handle == 0
|
91
|
+
raise SystemCallError, Fiddle.win32_last_error, "OpenProcess"
|
92
|
+
end
|
93
|
+
|
94
|
+
if NtResumeProcess.call(handle) != 0
|
95
|
+
raise SystemCallError, Fiddle.win32_last_error, "NtResumeProcess"
|
96
|
+
end
|
97
|
+
ensure
|
98
|
+
CloseHandle.call(handle) if handle
|
99
|
+
end
|
100
|
+
1 # For cross-platform compatibility
|
101
|
+
end
|
102
|
+
else
|
103
|
+
def resume(pid)
|
104
|
+
Process.kill('CONT', pid) if alive?(pid)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
Process.send(:extend, MoreCoreExtensions::ProcessPauseResume)
|
@@ -100,6 +100,21 @@ module MoreCoreExtensions
|
|
100
100
|
end
|
101
101
|
[]
|
102
102
|
end
|
103
|
+
|
104
|
+
# Create a deep clone of the object. This is similar to deep_dup
|
105
|
+
# but uses a Marshal based approach instead.
|
106
|
+
#
|
107
|
+
# h1 = {:a => "hello"}
|
108
|
+
# h2 = h1.deep_clone
|
109
|
+
#
|
110
|
+
# h1[:a] << " world"
|
111
|
+
#
|
112
|
+
# h1[:a] # "hello world"
|
113
|
+
# h2[:a] # "hello"
|
114
|
+
#
|
115
|
+
def deep_clone
|
116
|
+
Marshal.load(Marshal.dump(self))
|
117
|
+
end
|
103
118
|
end
|
104
119
|
end
|
105
120
|
end
|
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
|
|
22
22
|
|
23
23
|
spec.required_ruby_version = ">= 2.0.0"
|
24
24
|
|
25
|
-
spec.add_development_dependency "bundler"
|
25
|
+
spec.add_development_dependency "bundler"
|
26
26
|
spec.add_development_dependency "codeclimate-test-reporter"
|
27
27
|
spec.add_development_dependency "rake"
|
28
28
|
spec.add_development_dependency "rspec", ">= 3.0"
|
@@ -30,4 +30,5 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.add_development_dependency "timecop"
|
31
31
|
|
32
32
|
spec.add_runtime_dependency "activesupport"
|
33
|
+
spec.add_runtime_dependency "sync"
|
33
34
|
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:
|
4
|
+
version: 4.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason Frey
|
@@ -9,22 +9,22 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2020-07-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- - "
|
18
|
+
- - ">="
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: '
|
20
|
+
version: '0'
|
21
21
|
type: :development
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- - "
|
25
|
+
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: '
|
27
|
+
version: '0'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: codeclimate-test-reporter
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -109,6 +109,20 @@ dependencies:
|
|
109
109
|
- - ">="
|
110
110
|
- !ruby/object:Gem::Version
|
111
111
|
version: '0'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: sync
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
type: :runtime
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
112
126
|
description: MoreCoreExtensions are a set of core extensions beyond those provided
|
113
127
|
by ActiveSupport.
|
114
128
|
email:
|
@@ -133,6 +147,7 @@ files:
|
|
133
147
|
- lib/more_core_extensions.rb
|
134
148
|
- lib/more_core_extensions/all.rb
|
135
149
|
- lib/more_core_extensions/core_ext/array.rb
|
150
|
+
- lib/more_core_extensions/core_ext/array/compact_map.rb
|
136
151
|
- lib/more_core_extensions/core_ext/array/deletes.rb
|
137
152
|
- lib/more_core_extensions/core_ext/array/duplicates.rb
|
138
153
|
- lib/more_core_extensions/core_ext/array/element_counts.rb
|
@@ -140,12 +155,21 @@ files:
|
|
140
155
|
- lib/more_core_extensions/core_ext/array/math.rb
|
141
156
|
- lib/more_core_extensions/core_ext/array/nested.rb
|
142
157
|
- lib/more_core_extensions/core_ext/array/random.rb
|
158
|
+
- lib/more_core_extensions/core_ext/array/sorting.rb
|
143
159
|
- lib/more_core_extensions/core_ext/array/stretch.rb
|
144
160
|
- lib/more_core_extensions/core_ext/array/tableize.rb
|
161
|
+
- lib/more_core_extensions/core_ext/benchmark.rb
|
162
|
+
- lib/more_core_extensions/core_ext/benchmark/realtime_store.rb
|
163
|
+
- lib/more_core_extensions/core_ext/class.rb
|
164
|
+
- lib/more_core_extensions/core_ext/class/hierarchy.rb
|
165
|
+
- lib/more_core_extensions/core_ext/digest.rb
|
166
|
+
- lib/more_core_extensions/core_ext/digest/uuid.rb
|
145
167
|
- lib/more_core_extensions/core_ext/hash.rb
|
146
168
|
- lib/more_core_extensions/core_ext/hash/deletes.rb
|
147
169
|
- lib/more_core_extensions/core_ext/hash/nested.rb
|
148
170
|
- lib/more_core_extensions/core_ext/hash/sorting.rb
|
171
|
+
- lib/more_core_extensions/core_ext/math.rb
|
172
|
+
- lib/more_core_extensions/core_ext/math/slope.rb
|
149
173
|
- lib/more_core_extensions/core_ext/module.rb
|
150
174
|
- lib/more_core_extensions/core_ext/module/cache_with_timeout.rb
|
151
175
|
- lib/more_core_extensions/core_ext/module/namespace.rb
|
@@ -154,8 +178,9 @@ files:
|
|
154
178
|
- lib/more_core_extensions/core_ext/numeric/math.rb
|
155
179
|
- lib/more_core_extensions/core_ext/numeric/rounding.rb
|
156
180
|
- lib/more_core_extensions/core_ext/object.rb
|
157
|
-
- lib/more_core_extensions/core_ext/object/descendants.rb
|
158
181
|
- lib/more_core_extensions/core_ext/object/namespace.rb
|
182
|
+
- lib/more_core_extensions/core_ext/process.rb
|
183
|
+
- lib/more_core_extensions/core_ext/process/pause_resume.rb
|
159
184
|
- lib/more_core_extensions/core_ext/range.rb
|
160
185
|
- lib/more_core_extensions/core_ext/range/step_value.rb
|
161
186
|
- lib/more_core_extensions/core_ext/shared/nested.rb
|
@@ -187,8 +212,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
187
212
|
- !ruby/object:Gem::Version
|
188
213
|
version: '0'
|
189
214
|
requirements: []
|
190
|
-
|
191
|
-
rubygems_version: 2.7.6
|
215
|
+
rubygems_version: 3.0.6
|
192
216
|
signing_key:
|
193
217
|
specification_version: 4
|
194
218
|
summary: MoreCoreExtensions are a set of core extensions beyond those provided by
|
@@ -1,17 +0,0 @@
|
|
1
|
-
require 'active_support/core_ext/class/subclasses'
|
2
|
-
|
3
|
-
module MoreCoreExtensions
|
4
|
-
module Descendants
|
5
|
-
#
|
6
|
-
# Retrieve a descendant by its name
|
7
|
-
#
|
8
|
-
def descendant_get(desc_name)
|
9
|
-
return self if desc_name == name || desc_name.nil?
|
10
|
-
klass = descendants.find { |desc| desc.name == desc_name }
|
11
|
-
raise ArgumentError, "#{desc_name} is not a descendant of #{name}" unless klass
|
12
|
-
klass
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
Object.send(:include, MoreCoreExtensions::Descendants)
|