more_core_extensions 3.6.0 → 3.7.0

Sign up to get free protection for your applications and to get access to all the features.
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