more_core_extensions 3.3.0 → 3.4.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/.rubocop_local.yml +4 -0
- data/CHANGELOG.md +10 -1
- data/README.md +3 -0
- data/lib/more_core_extensions/core_ext/module.rb +1 -0
- data/lib/more_core_extensions/core_ext/module/cache_with_timeout.rb +101 -0
- data/lib/more_core_extensions/core_ext/shared/nested.rb +25 -17
- data/lib/more_core_extensions/version.rb +1 -1
- data/more_core_extensions.gemspec +1 -0
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 413a7851ecc9b2985a2186985d125319d91d7260
|
4
|
+
data.tar.gz: d8b660b117dca1de5e71a21184e75485942c8406
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ec665edef944f6aab6555c17bdb2c6e2ead4a0c782a107b45c096d3fd89a4aad81cf5fa54c9921a24048a70bdbcb3197d7e83ac4f48f0a672f1bfd6a7bebbf4d
|
7
|
+
data.tar.gz: baba9a0b258fc9097bb6759ca4af9d753a8fbc8e0475b9ef50676e464247df8bb5252fd8f92cf0abb23b72c52c884704c106d847625bfbf9ac5e9442f67b0d35
|
data/.rubocop_local.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,14 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
4
4
|
|
5
5
|
## [Unreleased]
|
6
6
|
|
7
|
+
## [3.4.0] - 2017-08-11
|
8
|
+
### Added
|
9
|
+
- Added Module#cache_with_timeout [[#51](https://github.com/ManageIQ/more_core_extensions/pull/51)]
|
10
|
+
|
11
|
+
### Changed
|
12
|
+
- Performance improvements to store_path [[#54](https://github.com/ManageIQ/more_core_extensions/pull/54)]
|
13
|
+
and fetch_path [[#55](https://github.com/ManageIQ/more_core_extensions/pull/55)]
|
14
|
+
|
7
15
|
## [3.3.0] - 2017-07-21
|
8
16
|
### Added
|
9
17
|
- Added Symbol#to_i [[#49](https://github.com/ManageIQ/more_core_extensions/pull/49)]
|
@@ -45,7 +53,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
45
53
|
- Upgraded to RSpec 3 [[#16](https://github.com/ManageIQ/more_core_extensions/pull/16)]
|
46
54
|
- Added the Change Log!
|
47
55
|
|
48
|
-
[Unreleased]: https://github.com/ManageIQ/more_core_extensions/compare/v3.
|
56
|
+
[Unreleased]: https://github.com/ManageIQ/more_core_extensions/compare/v3.4.0...HEAD
|
57
|
+
[3.4.0]: https://github.com/ManageIQ/more_core_extensions/compare/v3.3.0...v3.4.0
|
49
58
|
[3.3.0]: https://github.com/ManageIQ/more_core_extensions/compare/v3.2.0...v3.3.0
|
50
59
|
[3.2.0]: https://github.com/ManageIQ/more_core_extensions/compare/v3.1.1...v3.2.0
|
51
60
|
[3.1.1]: https://github.com/ManageIQ/more_core_extensions/compare/v3.1.0...v3.1.1
|
data/README.md
CHANGED
@@ -57,6 +57,9 @@ MoreCoreExtensions are a set of core extensions beyond those provided by ActiveS
|
|
57
57
|
|
58
58
|
#### Module
|
59
59
|
|
60
|
+
* core_ext/module/cache_with_timeout.rb
|
61
|
+
* `#cache_with_timeout` - Creates singleton methods that cache the results of the given block, but only for a short amount of time.
|
62
|
+
* `.clear_all_cache_with_timeout` - Globally clears all cached values across all classes.
|
60
63
|
* core_ext/module/namespace.rb
|
61
64
|
* `#namespace` - Returns an Array with the namespace to the current Module
|
62
65
|
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'sync'
|
2
|
+
|
3
|
+
$cache_with_timeout = {}
|
4
|
+
$cache_with_timeout_lock = Sync.new
|
5
|
+
|
6
|
+
module MoreCoreExtensions
|
7
|
+
module CacheWithTimeout
|
8
|
+
# cache_with_timeout creates singleton methods that cache the
|
9
|
+
# results of the given block, but only for a short amount of time.
|
10
|
+
# If the method is called again after time has passed, then the
|
11
|
+
# cache is cleared and the block is reevaluated. Note that the
|
12
|
+
# cache is only cleared on the next invocation after the time has
|
13
|
+
# passed, so if the block retains references to large objects,
|
14
|
+
# they will never be garbage collected if the method is never
|
15
|
+
# called again.
|
16
|
+
#
|
17
|
+
# The methods created are
|
18
|
+
# - `method`
|
19
|
+
# - `#{method}_clear_cache` - Will clear the cached value on demand
|
20
|
+
# - `#{method}_cached?` - Says whether or not there is a value cached
|
21
|
+
#
|
22
|
+
# Example:
|
23
|
+
# class Foo
|
24
|
+
# cache_with_timeout(:expensive_operation) do
|
25
|
+
# sleep 100
|
26
|
+
# rand(100)
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# Foo.expensive_operation # => 42
|
31
|
+
# Foo.expensive_operation # => 42
|
32
|
+
# # ... wait 5+ minutes ...
|
33
|
+
# Foo.expensive_operation # => 18
|
34
|
+
#
|
35
|
+
# @param [String|Symbol] method The name of the method to create.
|
36
|
+
# @param [Integer] timeout The number of seconds after which the cache is
|
37
|
+
# cleared (defaults to: 300 (5 minutes))
|
38
|
+
# @returns [Symbol] The name of the method created.
|
39
|
+
def cache_with_timeout(method, timeout = nil, &block)
|
40
|
+
raise "no block given" if block.nil?
|
41
|
+
raise ArgumentError, "method must be a Symbol" unless method.respond_to?(:to_sym)
|
42
|
+
|
43
|
+
key = "#{name}.#{method}".to_sym
|
44
|
+
|
45
|
+
$cache_with_timeout_lock.synchronize(:EX) do
|
46
|
+
$cache_with_timeout[key] = {}
|
47
|
+
end
|
48
|
+
|
49
|
+
define_singleton_method(method) do |*args|
|
50
|
+
force_reload = args.first
|
51
|
+
return $cache_with_timeout_lock.synchronize(:EX) do
|
52
|
+
cache = $cache_with_timeout[key]
|
53
|
+
|
54
|
+
old_timeout = cache[:timeout]
|
55
|
+
cache.clear if force_reload || (old_timeout && Time.now.utc > old_timeout)
|
56
|
+
break cache[:value] if cache.key?(:value)
|
57
|
+
|
58
|
+
new_timeout = timeout || 300 # 5 minutes
|
59
|
+
new_timeout = new_timeout.call if new_timeout.kind_of?(Proc)
|
60
|
+
new_timeout = Time.now.utc + new_timeout
|
61
|
+
new_value = block.call
|
62
|
+
|
63
|
+
cache[:timeout] = new_timeout
|
64
|
+
cache[:value] = new_value
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
define_singleton_method("#{method}_clear_cache") do |*_args|
|
69
|
+
$cache_with_timeout_lock.synchronize(:EX) do
|
70
|
+
$cache_with_timeout[key].clear
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
define_singleton_method("#{method}_cached?") do |*_args|
|
75
|
+
$cache_with_timeout_lock.synchronize(:EX) do
|
76
|
+
!$cache_with_timeout[key].empty?
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
method.to_sym
|
81
|
+
end
|
82
|
+
|
83
|
+
module ClassMethods
|
84
|
+
# Globally clears all cached values across all classes. This is
|
85
|
+
# mostly useful for testing to avoid test contamination.
|
86
|
+
#
|
87
|
+
# Example:
|
88
|
+
# RSpec.configure do |c|
|
89
|
+
# c.after { Module.clear_all_cache_with_timeout }
|
90
|
+
# end
|
91
|
+
def clear_all_cache_with_timeout
|
92
|
+
$cache_with_timeout_lock.synchronize(:EX) do
|
93
|
+
$cache_with_timeout.each_value(&:clear)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
Module.send(:include, MoreCoreExtensions::CacheWithTimeout)
|
101
|
+
Module.send(:extend, MoreCoreExtensions::CacheWithTimeout::ClassMethods)
|
@@ -26,13 +26,17 @@ module MoreCoreExtensions
|
|
26
26
|
args = args.first if args.length == 1 && args.first.kind_of?(Array)
|
27
27
|
raise ArgumentError, "must pass at least one key" if args.empty?
|
28
28
|
|
29
|
-
|
30
|
-
|
29
|
+
result = self
|
30
|
+
args.each_with_index do |key, i|
|
31
|
+
raise ArgumentError, "must be a number" if result.kind_of?(Array) && !key.kind_of?(Numeric)
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
result = result[key]
|
34
|
+
if !result.respond_to?(:fetch_path) && (i + 1) != args.size
|
35
|
+
result = nil
|
36
|
+
break
|
37
|
+
end
|
38
|
+
end
|
39
|
+
result
|
36
40
|
end
|
37
41
|
|
38
42
|
#
|
@@ -62,21 +66,25 @@ module MoreCoreExtensions
|
|
62
66
|
def store_path(*args)
|
63
67
|
raise ArgumentError, "must pass at least one key, and a value" if args.length < 2
|
64
68
|
value = args.pop
|
65
|
-
|
69
|
+
child = self
|
70
|
+
key = args.first
|
66
71
|
|
67
|
-
|
68
|
-
|
72
|
+
if args.length > 1 || args.first.kind_of?(Array)
|
73
|
+
keys = args.first.kind_of?(Array) ? args.first : args
|
74
|
+
keys.each_with_index do |cur_key, i|
|
75
|
+
raise ArgumentError, "must be a number" if child.kind_of?(Array) && !cur_key.kind_of?(Numeric)
|
76
|
+
key = cur_key # keep track of this for value assignment later
|
77
|
+
break if i + 1 == keys.size
|
69
78
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
self[key] = self.class.new
|
76
|
-
child = self[key]
|
79
|
+
unless child[cur_key].respond_to?(:store_path)
|
80
|
+
child[cur_key] = child.class.new
|
81
|
+
end
|
82
|
+
|
83
|
+
child = child[cur_key]
|
77
84
|
end
|
78
|
-
child.store_path(args[1..-1].push, value)
|
79
85
|
end
|
86
|
+
|
87
|
+
child[key] = value
|
80
88
|
end
|
81
89
|
|
82
90
|
#
|
@@ -27,6 +27,7 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_development_dependency "rake"
|
28
28
|
spec.add_development_dependency "rspec", ">= 3.0"
|
29
29
|
spec.add_development_dependency "simplecov"
|
30
|
+
spec.add_development_dependency "timecop"
|
30
31
|
|
31
32
|
spec.add_runtime_dependency "activesupport"
|
32
33
|
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: 3.
|
4
|
+
version: 3.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason Frey
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2017-
|
12
|
+
date: 2017-08-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -81,6 +81,20 @@ dependencies:
|
|
81
81
|
- - ">="
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: '0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: timecop
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
84
98
|
- !ruby/object:Gem::Dependency
|
85
99
|
name: activesupport
|
86
100
|
requirement: !ruby/object:Gem::Requirement
|
@@ -133,6 +147,7 @@ files:
|
|
133
147
|
- lib/more_core_extensions/core_ext/hash/nested.rb
|
134
148
|
- lib/more_core_extensions/core_ext/hash/sorting.rb
|
135
149
|
- lib/more_core_extensions/core_ext/module.rb
|
150
|
+
- lib/more_core_extensions/core_ext/module/cache_with_timeout.rb
|
136
151
|
- lib/more_core_extensions/core_ext/module/namespace.rb
|
137
152
|
- lib/more_core_extensions/core_ext/numeric.rb
|
138
153
|
- lib/more_core_extensions/core_ext/numeric/clamp.rb
|
@@ -173,7 +188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
173
188
|
version: '0'
|
174
189
|
requirements: []
|
175
190
|
rubyforge_project:
|
176
|
-
rubygems_version: 2.
|
191
|
+
rubygems_version: 2.6.11
|
177
192
|
signing_key:
|
178
193
|
specification_version: 4
|
179
194
|
summary: MoreCoreExtensions are a set of core extensions beyond those provided by
|