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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8445d02cce0bc6bc1cfc1554bd6db773e335c2f8
4
- data.tar.gz: 010cb3f4eb19a5d6c36a7593e77d65012b48e8c8
3
+ metadata.gz: 413a7851ecc9b2985a2186985d125319d91d7260
4
+ data.tar.gz: d8b660b117dca1de5e71a21184e75485942c8406
5
5
  SHA512:
6
- metadata.gz: 4731d3a3029b3aa664031f4c794ce22f57da5c4718dd6c6bd4810b0a98a112d19028c3d7ca1400c64568f3505d6e6798dd76b4eec59e106bbedba7637b894a84
7
- data.tar.gz: f0660e800d33a9d89c02a84e21825b7ed0ff7712594844dc3b5159dc1d0dbf960023a15005221501aabe5aa0255d9986c2e9f8e64497e1ecd673c25841b63489
6
+ metadata.gz: ec665edef944f6aab6555c17bdb2c6e2ead4a0c782a107b45c096d3fd89a4aad81cf5fa54c9921a24048a70bdbcb3197d7e83ac4f48f0a672f1bfd6a7bebbf4d
7
+ data.tar.gz: baba9a0b258fc9097bb6759ca4af9d753a8fbc8e0475b9ef50676e464247df8bb5252fd8f92cf0abb23b72c52c884704c106d847625bfbf9ac5e9442f67b0d35
@@ -0,0 +1,4 @@
1
+ GlobalVars:
2
+ AllowedVariables:
3
+ - $cache_with_timeout
4
+ - $cache_with_timeout_lock
@@ -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.3.0...HEAD
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
 
@@ -1 +1,2 @@
1
+ require 'more_core_extensions/core_ext/module/cache_with_timeout'
1
2
  require 'more_core_extensions/core_ext/module/namespace'
@@ -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
- key = args.first
30
- raise ArgumentError, "must be a number" if self.kind_of?(Array) && !key.kind_of?(Numeric)
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
- child = self[key]
33
- return child if args.length == 1
34
- return nil unless child.respond_to?(:fetch_path)
35
- return child.fetch_path(args[1..-1])
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
- args = args.first if args.length == 1 && args.first.kind_of?(Array)
69
+ child = self
70
+ key = args.first
66
71
 
67
- key = args.first
68
- raise ArgumentError, "must be a number" if self.kind_of?(Array) && !key.kind_of?(Numeric)
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
- if args.length == 1
71
- self[key] = value
72
- else
73
- child = self[key]
74
- unless child.respond_to?(:store_path)
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
  #
@@ -1,3 +1,3 @@
1
1
  module MoreCoreExtensions
2
- VERSION = "3.3.0".freeze
2
+ VERSION = "3.4.0".freeze
3
3
  end
@@ -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.3.0
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-07-24 00:00:00.000000000 Z
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.5.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