more_core_extensions 3.6.0 → 3.7.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 +5 -5
- data/.travis.yml +7 -5
- data/CHANGELOG.md +9 -1
- data/README.md +6 -0
- data/bin/console +1 -1
- data/lib/more_core_extensions/all.rb +4 -0
- 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 +30 -0
- data/lib/more_core_extensions/core_ext/enumerable.rb +1 -0
- data/lib/more_core_extensions/core_ext/enumerable/sorting.rb +39 -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/version.rb +1 -1
- data/more_core_extensions.gemspec +1 -1
- metadata +15 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 45280e85179a5cec518a1a078c3ef57502042771
|
4
|
+
data.tar.gz: a38d6af1cc7f313f4f0254fd466ba3c8309d42cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ca86d8e6a9a9ff26fbc1a6a5ad96d2b7ef05dc637f9474f0f160bee51b38e97d625cbc6ff85c7765886f38947b924f528c54ea7c99fa3e2fe1a4fcadac2e706b
|
7
|
+
data.tar.gz: 68af4c4bb3230ece550bc6908016bd4faf5f2f495f4c9e9871704203aeac84fa83b576fa6654d20444f3197b5ce4b57c9bb988f87a6cdbe466ce073e4ddca8ca
|
data/.travis.yml
CHANGED
@@ -1,18 +1,20 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
3
|
- "2.0"
|
4
|
-
- "2.1"
|
5
|
-
- "2.2"
|
6
|
-
- "2.3.
|
7
|
-
- "2.4.
|
4
|
+
- "2.1.10"
|
5
|
+
- "2.2.10"
|
6
|
+
- "2.3.8"
|
7
|
+
- "2.4.5"
|
8
|
+
- "2.5.3"
|
9
|
+
- "2.6.0"
|
8
10
|
- ruby-head
|
9
11
|
- jruby-head
|
10
12
|
sudo: false
|
11
13
|
cache: bundler
|
12
|
-
before_install: gem install bundler -v ">= 1.13.6"
|
13
14
|
after_script: bundle exec codeclimate-test-reporter
|
14
15
|
matrix:
|
15
16
|
allow_failures:
|
17
|
+
- rvm: "2.6.0"
|
16
18
|
- rvm: ruby-head
|
17
19
|
- rvm: jruby-head
|
18
20
|
fast_finish: true
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,13 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
4
4
|
|
5
5
|
## [Unreleased]
|
6
6
|
|
7
|
+
## [3.7.0] - 2019-02-04
|
8
|
+
### Added
|
9
|
+
- Added Enumerable#stable_sort_by [[#67](https://github.com/ManageIQ/more_core_extensions/pull/67)]
|
10
|
+
- Added Math#slope_y_intercept, #slope_x_intercept, #linear_regression [[#50](https://github.com/ManageIQ/more_core_extensions/pull/50)]
|
11
|
+
- Added Benchmark#realtime_store, #realtime_block and helper methods [[#65](https://github.com/ManageIQ/more_core_extensions/pull/65)]
|
12
|
+
- Added Class#hierarchy and #lineage [[#61](https://github.com/ManageIQ/more_core_extensions/pull/61)]
|
13
|
+
|
7
14
|
## [3.6.0] - 2018-03-01
|
8
15
|
### Added
|
9
16
|
- Added String#decimal_si_to_big_decimal [[#59](https://github.com/ManageIQ/more_core_extensions/pull/59)]
|
@@ -61,7 +68,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
61
68
|
- Upgraded to RSpec 3 [[#16](https://github.com/ManageIQ/more_core_extensions/pull/16)]
|
62
69
|
- Added the Change Log!
|
63
70
|
|
64
|
-
[Unreleased]: https://github.com/ManageIQ/more_core_extensions/compare/v3.
|
71
|
+
[Unreleased]: https://github.com/ManageIQ/more_core_extensions/compare/v3.7.0...HEAD
|
72
|
+
[3.7.0]: https://github.com/ManageIQ/more_core_extensions/compare/v3.6.0...v3.7.0
|
65
73
|
[3.6.0]: https://github.com/ManageIQ/more_core_extensions/compare/v3.5.0...v3.6.0
|
66
74
|
[3.5.0]: https://github.com/ManageIQ/more_core_extensions/compare/v3.4.0...v3.5.0
|
67
75
|
[3.4.0]: https://github.com/ManageIQ/more_core_extensions/compare/v3.3.0...v3.4.0
|
data/README.md
CHANGED
@@ -44,6 +44,12 @@ MoreCoreExtensions are a set of core extensions beyond those provided by ActiveS
|
|
44
44
|
* core_ext/array/tableize.rb
|
45
45
|
* `#tableize` - Create a string representation of receiver in a tabular format if receiver is an Array of Arrays or an Array of Hashes
|
46
46
|
|
47
|
+
#### Class
|
48
|
+
|
49
|
+
* core_ext/class/hierarchy.rb
|
50
|
+
* `#hierarchy` - Returns a tree-like Hash structure of all descendants.
|
51
|
+
* `#lineage` - Returns an Array of all superclasses.
|
52
|
+
|
47
53
|
#### Hash
|
48
54
|
|
49
55
|
* core_ext/hash/deletes.rb
|
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,7 +1,11 @@
|
|
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/enumerable'
|
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'
|
@@ -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,30 @@
|
|
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 a tree-like Hash structure of all descendants.
|
7
|
+
#
|
8
|
+
# require 'socket'
|
9
|
+
# IO.hierarchy
|
10
|
+
# # => {BasicSocket=>
|
11
|
+
# # {Socket=>{},
|
12
|
+
# # IPSocket=>{TCPSocket=>{TCPServer=>{}}, UDPSocket=>{}},
|
13
|
+
# # UNIXSocket=>{UNIXServer=>{}}},
|
14
|
+
# # File=>{}}
|
15
|
+
def hierarchy
|
16
|
+
subclasses.each_with_object({}) { |k, h| h[k] = k.hierarchy }
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns an Array of all superclasses.
|
20
|
+
#
|
21
|
+
# require 'socket'
|
22
|
+
# TCPServer.lineage
|
23
|
+
# # => [TCPSocket, IPSocket, BasicSocket, IO, Object, BasicObject]
|
24
|
+
def lineage
|
25
|
+
superclass.nil? ? [] : superclass.lineage.unshift(superclass)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Class.send(:include, MoreCoreExtensions::ClassHierarchy)
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'more_core_extensions/core_ext/enumerable/sorting'
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module MoreCoreExtensions
|
2
|
+
module StableSorting
|
3
|
+
def self.included(klass)
|
4
|
+
klass.class_eval do
|
5
|
+
def stable_sort_by(col_names = nil, order = nil, &block)
|
6
|
+
# stabilizer is needed because of
|
7
|
+
# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/170565
|
8
|
+
stabilizer = 0
|
9
|
+
nil_rows, sortable =
|
10
|
+
partition do |r|
|
11
|
+
Array(col_names).any? { |c| r[c].nil? }
|
12
|
+
end
|
13
|
+
|
14
|
+
data_array =
|
15
|
+
if col_names
|
16
|
+
sortable.sort_by do |r|
|
17
|
+
stabilizer += 1
|
18
|
+
[Array(col_names).map do |col|
|
19
|
+
val = r[col]
|
20
|
+
val = val.downcase if val.kind_of?(String)
|
21
|
+
val = val.to_s if val.kind_of?(FalseClass) || val.kind_of?(TrueClass)
|
22
|
+
val
|
23
|
+
end, stabilizer]
|
24
|
+
end
|
25
|
+
else
|
26
|
+
sortable.sort_by(&block)
|
27
|
+
end.to_a
|
28
|
+
|
29
|
+
data_array += nil_rows
|
30
|
+
|
31
|
+
data_array.reverse! if order == :descending
|
32
|
+
data_array
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
Enumerable.send(:include, MoreCoreExtensions::StableSorting)
|
@@ -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)
|
@@ -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"
|
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.7.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: 2019-02-04 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
|
@@ -142,10 +142,18 @@ files:
|
|
142
142
|
- lib/more_core_extensions/core_ext/array/random.rb
|
143
143
|
- lib/more_core_extensions/core_ext/array/stretch.rb
|
144
144
|
- lib/more_core_extensions/core_ext/array/tableize.rb
|
145
|
+
- lib/more_core_extensions/core_ext/benchmark.rb
|
146
|
+
- lib/more_core_extensions/core_ext/benchmark/realtime_store.rb
|
147
|
+
- lib/more_core_extensions/core_ext/class.rb
|
148
|
+
- lib/more_core_extensions/core_ext/class/hierarchy.rb
|
149
|
+
- lib/more_core_extensions/core_ext/enumerable.rb
|
150
|
+
- lib/more_core_extensions/core_ext/enumerable/sorting.rb
|
145
151
|
- lib/more_core_extensions/core_ext/hash.rb
|
146
152
|
- lib/more_core_extensions/core_ext/hash/deletes.rb
|
147
153
|
- lib/more_core_extensions/core_ext/hash/nested.rb
|
148
154
|
- lib/more_core_extensions/core_ext/hash/sorting.rb
|
155
|
+
- lib/more_core_extensions/core_ext/math.rb
|
156
|
+
- lib/more_core_extensions/core_ext/math/slope.rb
|
149
157
|
- lib/more_core_extensions/core_ext/module.rb
|
150
158
|
- lib/more_core_extensions/core_ext/module/cache_with_timeout.rb
|
151
159
|
- lib/more_core_extensions/core_ext/module/namespace.rb
|
@@ -188,7 +196,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
188
196
|
version: '0'
|
189
197
|
requirements: []
|
190
198
|
rubyforge_project:
|
191
|
-
rubygems_version: 2.
|
199
|
+
rubygems_version: 2.6.14.3
|
192
200
|
signing_key:
|
193
201
|
specification_version: 4
|
194
202
|
summary: MoreCoreExtensions are a set of core extensions beyond those provided by
|