short_circu_it 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: fcdddba43f8cac401f3a4d6998089348572453118ac95231bdf25e669b7a8316
4
+ data.tar.gz: 1077aedbd2bebdc80cf08583e0b2e0ba549cd4b7ff3876b37364494d7e4a550c
5
+ SHA512:
6
+ metadata.gz: '0388a2743f8cf78f1146fab8843340eb087b0e55c687a525ea543bed09e8db366d162d962937e7fcb80922664aa33f067914ebadc768e414b3c8159bb00ca787'
7
+ data.tar.gz: 819206d14daa6a4c218262a48754cb270eaa375ab4128b90b332139436f77eb1bd52c8f1a4768325b40838a1a7179a3dcafde440c69d8f0e6f096ff28ccc8f0f
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Allen Rettberg
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # ShortCircuIt
2
+
3
+ [![Build Status](https://semaphoreci.com/api/v1/freshly/spicerack/branches/master/badge.svg)](https://semaphoreci.com/freshly/spicerack)
4
+ [![Maintainability](https://api.codeclimate.com/v1/badges/7e089c2617c530a85b17/maintainability)](https://codeclimate.com/github/Freshly/spicerack/maintainability)
5
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/7e089c2617c530a85b17/test_coverage)](https://codeclimate.com/github/Freshly/spicerack/test_coverage)
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'short_circu_it'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install short_circu_it
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/Freshly/spicerack.
36
+
37
+ ## License
38
+
39
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "short_circu_it/version"
4
+ require "short_circu_it/memoization_store"
5
+ require "active_support/core_ext/module"
6
+ require "active_support/core_ext/array"
7
+ require "active_support/concern"
8
+ require "around_the_world"
9
+
10
+ module ShortCircuIt
11
+ extend ActiveSupport::Concern
12
+ include AroundTheWorld
13
+
14
+ PREPEND_MODULE_NAME = "MemoizedMethods"
15
+
16
+ included do
17
+ delegate :memoization_observers, to: :class
18
+ delegate :clear_memoization, :clear_all_memoization, to: :memoization_store
19
+ end
20
+
21
+ private
22
+
23
+ # @return [ShortCircuIt::MemoizationStore]
24
+ def memoization_store
25
+ @memoization_store ||= MemoizationStore.new(self)
26
+ end
27
+
28
+ class_methods do
29
+ attr_internal_reader :memoization_observers
30
+
31
+ protected
32
+
33
+ # @example
34
+ # def expensive_method
35
+ # puts "doing some really expensive operation here!"
36
+ # "these datas are yuuge"
37
+ # end
38
+ # memoize :expensive_method
39
+ #
40
+ # expensive_method
41
+ # doing some really expensive operation here!
42
+ # => "these datas are yuuge"
43
+ # expensive_method
44
+ # => "these datas are yuuge"
45
+ #
46
+ # @example
47
+ # def some_association
48
+ # SomeAssociation.find(some_association_id)
49
+ # end
50
+ # memoize :some_association, observes: :some_association_id
51
+ #
52
+ # some_association_id = 1
53
+ # some_association
54
+ # * database stuff *
55
+ # => #<SomeAssociation:1234 id: 1>
56
+ #
57
+ # some_association
58
+ # * no database stuff *
59
+ # => #<SomeAssociation:1234 id: 1>
60
+ #
61
+ # some_association_id = 2
62
+ # some_association
63
+ # * database stuff *
64
+ # => #<SomeAssociation:2468 id: 2>
65
+ #
66
+ # @param method_name [Symbol] The name of the method to be memoized
67
+ # @param :observes [Symbol, Array<Symbol>] A method or array of methods to be observed to determine memoization
68
+ # cache validity. If any of the observed values change, the cached
69
+ # value will be invalidated. By default, the object will observe itself.
70
+ def memoize(method_name, observes: :itself)
71
+ add_memoized_observers(method_name.to_sym, observes)
72
+
73
+ around_method method_name.to_sym, PREPEND_MODULE_NAME do |*args|
74
+ memoization_store.memoize(method_name.to_sym, args.hash) do
75
+ super(*args)
76
+ end
77
+ end
78
+ end
79
+
80
+ private
81
+
82
+ attr_internal_writer :memoization_observers
83
+
84
+ def add_memoized_observers(method_name, observers)
85
+ # TODO: Raise an error if method has already been memoized? A warning maybe?
86
+ self.memoization_observers ||= {}
87
+ self.memoization_observers = memoization_observers.
88
+ merge(method_name.to_sym => Array.wrap(observers).freeze).
89
+ freeze
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MemoizationStore
4
+ class NotMemoizedError < StandardError; end
5
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module"
4
+
5
+ module ShortCircuIt
6
+ class MemoizationStore
7
+ delegate :memoization_observers, to: :owner
8
+
9
+ # @param owner [*] The object being memoized
10
+ def initialize(owner)
11
+ @owner = owner
12
+ end
13
+
14
+ # @param method_name [Symbol] The name of the method being memoized.
15
+ # @param argument_hash [Integer] The hash value of the arguments passed to the method.
16
+ # @yield [] Yields to a given block with no arguments. Memoizes the value returned by the block.
17
+ # @return [*] The value returned either from the memoization cache if present, or yielded block if not.
18
+ def memoize(method_name, argument_hash)
19
+ return memoized_value(method_name, argument_hash) if memoized?(method_name, argument_hash)
20
+
21
+ clear_memoization(method_name) unless current_memoization_for_method?(method_name)
22
+
23
+ yield.tap do |returned_value|
24
+ current_memoization_for_method(method_name)[argument_hash] = returned_value
25
+ end
26
+ end
27
+
28
+ # Clears all cached values for the given method
29
+ #
30
+ # @param method_name [Symbol] The name of a memoized method
31
+ # @return [Boolean] True if a value was cleared, false if not
32
+ def clear_memoization(method_name)
33
+ !!memoized_hash.delete(method_name)
34
+ end
35
+
36
+ # Clears all memoized values on the object
37
+ def clear_all_memoization
38
+ memoized_hash.clear
39
+ end
40
+
41
+ def inspect
42
+ "#<#{self.class} memoized: #{memoized_hash.keys.inspect}>"
43
+ end
44
+
45
+ private
46
+
47
+ def memoized_hash
48
+ @memoized_hash ||= {}
49
+ end
50
+
51
+ def memoization_for_method(method_name)
52
+ memoized_hash[method_name] ||= {}
53
+ end
54
+
55
+ # @param method_name [Symbol] The name of the method to memoize
56
+ # @param argument_hash [Integer] The hash value of the arguments passed to the method
57
+ # @return [Boolean] True if the method has a current memoized value with the given arguments
58
+ def memoized?(method_name, argument_hash)
59
+ current_memoization_for_method?(method_name) && current_memoization_for_method(method_name).key?(argument_hash)
60
+ end
61
+
62
+ # @param method_name [String] The name of the method to memoize
63
+ # @param argument_hash [Integer] The hash value of the arguments passed to the method
64
+ # @return [*] The value that has been memoized for the method/argument combination
65
+ def memoized_value(method_name, argument_hash)
66
+ raise NotMemoizedError unless memoized?(method_name, argument_hash)
67
+
68
+ current_memoization_for_method(method_name)[argument_hash]
69
+ end
70
+
71
+ # @param method_name [Symbol] The name of a memoized method
72
+ # @return [Hash] A hash of memoized values for the current state of the observed objects for the given method.
73
+ def current_memoization_for_method(method_name)
74
+ memoization_for_method(method_name)[state_hash(method_name)] ||= {}
75
+ end
76
+
77
+ # @param method_name [Symbol] The name of a memoized method
78
+ # @return [Boolean] True if there are any memoized values for the current state of the observed objects.
79
+ def current_memoization_for_method?(method_name)
80
+ memoization_for_method(method_name).key?(state_hash(method_name))
81
+ end
82
+
83
+ # @param method_name [Symbol] The name of a memoized method
84
+ # @return [Integer] The hash value of all observed objects for the given method.
85
+ def state_hash(method_name)
86
+ memoization_observers[method_name].map { |observed_method| owner.public_send(observed_method) }.hash
87
+ end
88
+
89
+ attr_reader :owner
90
+ end
91
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShortCircuIt
4
+ VERSION = "0.3.0"
5
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: short_circu_it
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Allen Rettberg
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-10-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 5.1.6
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 5.1.6
27
+ - !ruby/object:Gem::Dependency
28
+ name: around_the_world
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.2.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.2.0
41
+ description: Memoize methods safely with parameter and dependency observation
42
+ email:
43
+ - allen.rettberg@freshly.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - LICENSE.txt
49
+ - README.md
50
+ - lib/short_circu_it.rb
51
+ - lib/short_circu_it/errors.rb
52
+ - lib/short_circu_it/memoization_store.rb
53
+ - lib/short_circu_it/version.rb
54
+ homepage: https://www.freshly.com/
55
+ licenses:
56
+ - MIT
57
+ metadata: {}
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ requirements: []
73
+ rubyforge_project:
74
+ rubygems_version: 2.7.6
75
+ signing_key:
76
+ specification_version: 4
77
+ summary: Effortless memoization
78
+ test_files: []