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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 605b41f75443bf69e235fccd80b9b94c48cbf44f95e5205ea540d5b36a84a75d
4
- data.tar.gz: 8cd816257ef3a0e564960273a65415173c207a962fe0aa8e681b4b83565edc12
2
+ SHA1:
3
+ metadata.gz: 45280e85179a5cec518a1a078c3ef57502042771
4
+ data.tar.gz: a38d6af1cc7f313f4f0254fd466ba3c8309d42cd
5
5
  SHA512:
6
- metadata.gz: a6300d6be1bc10872dbc485160f1c51a2b388fa687e160944712d27d2ef12f41a98e122697855ff8fca3ea87a9f2f2b3d4cfacc9e83286d0f3559cf4375a56a9
7
- data.tar.gz: 76554a13bfcce20c1a7b361185f7215c552e7306b747168b8d3a21ae19d0908b6d02d30c91f127f1823f3bee5d5a5143721972e3d3252ece8f6ccd5e5ebe284e
6
+ metadata.gz: ca86d8e6a9a9ff26fbc1a6a5ad96d2b7ef05dc637f9474f0f160bee51b38e97d625cbc6ff85c7765886f38947b924f528c54ea7c99fa3e2fe1a4fcadac2e706b
7
+ data.tar.gz: 68af4c4bb3230ece550bc6908016bd4faf5f2f495f4c9e9871704203aeac84fa83b576fa6654d20444f3197b5ce4b57c9bb988f87a6cdbe466ce073e4ddca8ca
@@ -1,18 +1,20 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - "2.0"
4
- - "2.1"
5
- - "2.2"
6
- - "2.3.3"
7
- - "2.4.0"
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
@@ -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.6.0...HEAD
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
@@ -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)
@@ -1,3 +1,3 @@
1
1
  module MoreCoreExtensions
2
- VERSION = "3.6.0".freeze
2
+ VERSION = "3.7.0".freeze
3
3
  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", "~> 1.3"
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.6.0
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: 2018-03-01 00:00:00.000000000 Z
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: '1.3'
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: '1.3'
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.7.6
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