memoist-0.16.0/0000755000004100000410000000000013130050477013303 5ustar www-datawww-datamemoist-0.16.0/Rakefile0000644000004100000410000000032313130050477014746 0ustar www-datawww-data# encoding: utf-8 require 'bundler/gem_tasks' require 'rake/testtask' Rake::TestTask.new do |t| t.libs << 'test' t.test_files = FileList['test/**/*_test.rb'] t.verbose = true end task default: ['test'] memoist-0.16.0/Gemfile0000644000004100000410000000013413130050477014574 0ustar www-datawww-datasource 'https://rubygems.org' # Specify your gem's dependencies in memoist.gemspec gemspec memoist-0.16.0/script/0000755000004100000410000000000013130050477014607 5ustar www-datawww-datamemoist-0.16.0/script/benchmark.rb0000644000004100000410000000146613130050477017075 0ustar www-datawww-data$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib') require 'benchmark/ips' require 'memoist' class Benchy extend Memoist def arity_0 'Hello World' end memoize :arity_0 def arity_1(name) "Hello #{name}" end memoize :arity_1 end OBJECT = Benchy.new puts "Benchmarking: #{Memoist::VERSION}" Benchmark.ips do |x| x.report('arity 0 - memoized') do |times| times.times do OBJECT.arity_0 end end # x.report("arity 0 - unmemoized") do |times| # times.times do # OBJECT._unmemoized_arity_0 # end # end x.report('arity 1 - memoized') do |times| times.times do OBJECT.arity_1(:World) end end # x.report("arity 1 - unmemoized") do |times| # times.times do # OBJECT._unmemoized_arity_1(:World) # end # end end memoist-0.16.0/LICENSE.md0000644000004100000410000000205413130050477014710 0ustar www-datawww-dataCopyright (c) 2012-2013 Matthew Rudy Jacobs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. memoist-0.16.0/.travis.yml0000644000004100000410000000047113130050477015416 0ustar www-datawww-datasudo: false cache: bundler language: ruby rvm: - 1.8.7 - 1.9.2 - 1.9.3 - 2.0.0 - 2.1.10 - 2.2.7 - 2.3.4 - 2.4.1 - ruby-head - jruby-18mode - jruby-19mode - jruby-9.1.5.0 - jruby-head before_install: - gem install bundler --no-document -v '~> 1.13' before_script: - unset JRUBY_OPTS memoist-0.16.0/lib/0000755000004100000410000000000013130050477014051 5ustar www-datawww-datamemoist-0.16.0/lib/memoist/0000755000004100000410000000000013130050477015526 5ustar www-datawww-datamemoist-0.16.0/lib/memoist/core_ext/0000755000004100000410000000000013130050477017336 5ustar www-datawww-datamemoist-0.16.0/lib/memoist/core_ext/singleton_class.rb0000644000004100000410000000034513130050477023054 0ustar www-datawww-data# frozen_string_literal: true module Kernel # Returns the object's singleton class. unless respond_to?(:singleton_class) def singleton_class class << self self end end end # exists in 1.9.2 end memoist-0.16.0/lib/memoist/version.rb0000644000004100000410000000011613130050477017536 0ustar www-datawww-data# frozen_string_literal: true module Memoist VERSION = '0.16.0'.freeze end memoist-0.16.0/lib/memoist.rb0000644000004100000410000001475313130050477016065 0ustar www-datawww-data# frozen_string_literal: true require 'memoist/version' require 'memoist/core_ext/singleton_class' module Memoist def self.extended(extender) Memoist.memoist_eval(extender) do unless singleton_class.method_defined?(:memoized_methods) def self.memoized_methods @_memoized_methods ||= [] end end end end def self.memoized_ivar_for(method_name, identifier = nil) "@#{memoized_prefix(identifier)}_#{escape_punctuation(method_name)}" end def self.unmemoized_method_for(method_name, identifier = nil) "#{unmemoized_prefix(identifier)}_#{method_name}".to_sym end def self.memoized_prefix(identifier = nil) if identifier "_memoized_#{identifier}" else '_memoized'.freeze end end def self.unmemoized_prefix(identifier = nil) if identifier "_unmemoized_#{identifier}" else '_unmemoized'.freeze end end def self.escape_punctuation(string) string = string.is_a?(String) ? string.dup : string.to_s return string unless string.end_with?('?'.freeze, '!'.freeze) # A String can't end in both ? and ! if string.sub!(/\?\Z/, '_query'.freeze) else string.sub!(/!\Z/, '_bang'.freeze) end string end def self.memoist_eval(klass, *args, &block) if klass.respond_to?(:class_eval) klass.class_eval(*args, &block) else klass.singleton_class.class_eval(*args, &block) end end def self.extract_reload!(method, args) if args.length == method.arity.abs + 1 && (args.last == true || args.last == :reload) reload = args.pop end reload end module InstanceMethods def memoize_all prime_cache end def unmemoize_all flush_cache end def memoized_structs(names) ref_obj = self.class.respond_to?(:class_eval) ? singleton_class : self structs = ref_obj.all_memoized_structs return structs if names.empty? structs.select { |s| names.include?(s.memoized_method) } end def prime_cache(*method_names) memoized_structs(method_names).each do |struct| if struct.arity == 0 __send__(struct.memoized_method) else instance_variable_set(struct.ivar, {}) end end end def flush_cache(*method_names) memoized_structs(method_names).each do |struct| remove_instance_variable(struct.ivar) if instance_variable_defined?(struct.ivar) end end end MemoizedMethod = Struct.new(:memoized_method, :ivar, :arity) def all_memoized_structs @all_memoized_structs ||= begin structs = memoized_methods.dup # Collect the memoized_methods of ancestors in ancestor order # unless we already have it since self or parents could be overriding # an ancestor method. ancestors.grep(Memoist).each do |ancestor| ancestor.memoized_methods.each do |m| structs << m unless structs.any? { |am| am.memoized_method == m.memoized_method } end end structs end end def clear_structs @all_memoized_structs = nil end def memoize(*method_names) identifier = method_names.pop[:identifier] if method_names.last.is_a?(Hash) method_names.each do |method_name| unmemoized_method = Memoist.unmemoized_method_for(method_name, identifier) memoized_ivar = Memoist.memoized_ivar_for(method_name, identifier) Memoist.memoist_eval(self) do include InstanceMethods if method_defined?(unmemoized_method) warn "Already memoized #{method_name}" return end alias_method unmemoized_method, method_name mm = MemoizedMethod.new(method_name, memoized_ivar, instance_method(method_name).arity) memoized_methods << mm if mm.arity == 0 # define a method like this; # def mime_type(reload=true) # skip_cache = reload || !instance_variable_defined?("@_memoized_mime_type") # set_cache = skip_cache && !frozen? # # if skip_cache # value = _unmemoized_mime_type # else # value = @_memoized_mime_type # end # # if set_cache # @_memoized_mime_type = value # end # # value # end module_eval <<-EOS, __FILE__, __LINE__ + 1 def #{method_name}(reload = false) skip_cache = reload || !instance_variable_defined?("#{memoized_ivar}") set_cache = skip_cache && !frozen? if skip_cache value = #{unmemoized_method} else value = #{memoized_ivar} end if set_cache #{memoized_ivar} = value end value end EOS else # define a method like this; # def mime_type(*args) # reload = Memoist.extract_reload!(method(:_unmemoized_mime_type), args) # # skip_cache = reload || !memoized_with_args?(:mime_type, args) # set_cache = skip_cache && !frozen # # if skip_cache # value = _unmemoized_mime_type(*args) # else # value = @_memoized_mime_type[args] # end # # if set_cache # @_memoized_mime_type ||= {} # @_memoized_mime_type[args] = value # end # # value # end module_eval <<-EOS, __FILE__, __LINE__ + 1 def #{method_name}(*args) reload = Memoist.extract_reload!(method(#{unmemoized_method.inspect}), args) skip_cache = reload || !(instance_variable_defined?(#{memoized_ivar.inspect}) && #{memoized_ivar} && #{memoized_ivar}.has_key?(args)) set_cache = skip_cache && !frozen? if skip_cache value = #{unmemoized_method}(*args) else value = #{memoized_ivar}[args] end if set_cache #{memoized_ivar} ||= {} #{memoized_ivar}[args] = value end value end EOS end if private_method_defined?(unmemoized_method) private method_name elsif protected_method_defined?(unmemoized_method) protected method_name end end end # return a chainable method_name symbol if we can method_names.length == 1 ? method_names.first : method_names end end memoist-0.16.0/memoist.gemspec0000644000004100000410000000326413130050477016332 0ustar www-datawww-data# coding: utf-8 lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'memoist/version' AUTHORS = [ ['Joshua Peek', 'josh@joshpeek.com'], ['Tarmo Tänav', 'tarmo@itech.ee'], ['Jeremy Kemper', 'jeremy@bitsweat.net'], ['Eugene Pimenov', 'libc@mac.com'], ['Xavier Noria', 'fxn@hashref.com'], ['Niels Ganser', 'niels@herimedia.co'], ['Carl Lerche & Yehuda Katz', 'wycats@gmail.com'], ['jeem', 'jeem@hughesorama.com'], ['Jay Pignata', 'john.pignata@gmail.com'], ['Damien Mathieu', '42@dmathieu.com'], ['José Valim', 'jose.valim@gmail.com'], ['Matthew Rudy Jacobs', 'matthewrudyjacobs@gmail.com'] ].freeze Gem::Specification.new do |spec| spec.name = 'memoist' spec.version = Memoist::VERSION spec.authors = AUTHORS.map { |name, _email| name } spec.email = AUTHORS.map { |_name, email| email } spec.summary = 'memoize methods invocation' spec.homepage = 'https://github.com/matthewrudy/memoist' spec.license = 'MIT' spec.files = `git ls-files -z`.split("\x0") spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ['lib'] spec.add_development_dependency 'benchmark-ips' spec.add_development_dependency 'bundler' if RUBY_VERSION < '1.9.3' spec.add_development_dependency 'rake', '~> 10.4' else spec.add_development_dependency 'rake' end spec.add_development_dependency 'minitest', '~> 5.10' end memoist-0.16.0/test/0000755000004100000410000000000013130050477014262 5ustar www-datawww-datamemoist-0.16.0/test/test_helper.rb0000644000004100000410000000014413130050477017124 0ustar www-datawww-datarequire 'minitest/autorun' $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib') memoist-0.16.0/test/memoist_test.rb0000644000004100000410000003460413130050477017332 0ustar www-datawww-datarequire 'test_helper' require 'memoist' class MemoistTest < Minitest::Test class CallCounter def initialize @calls = {} end def call(method_name) @calls[method_name] ||= 0 @calls[method_name] += 1 end def count(method_name) @calls[method_name] ||= 0 end end class Person extend Memoist def initialize @counter = CallCounter.new end def name_calls @counter.count(:name) end def student_name_calls @counter.count(:student_name) end def name_query_calls @counter.count(:name?) end def is_developer_calls @counter.count(:is_developer?) end def age_calls @counter.count(:age) end def name @counter.call(:name) 'Josh' end def name? @counter.call(:name?) true end memoize :name? def update(_name) 'Joshua' end memoize :update def age @counter.call(:age) nil end memoize :name, :age def sleep(hours = 8) @counter.call(:sleep) hours end memoize :sleep def sleep_calls @counter.count(:sleep) end def update_attributes(_options = {}) @counter.call(:update_attributes) true end memoize :update_attributes def update_attributes_calls @counter.count(:update_attributes) end protected def memoize_protected_test 'protected' end memoize :memoize_protected_test private def is_developer? @counter.call(:is_developer?) 'Yes' end memoize :is_developer? end class Student < Person def name @counter.call(:student_name) "Student #{super}" end memoize :name, identifier: :student end class Teacher < Person def seniority 'very_senior' end memoize :seniority end class Company attr_reader :name_calls def initialize @name_calls = 0 end def name @name_calls += 1 '37signals' end end module Rates extend Memoist attr_reader :sales_tax_calls def sales_tax(price) @sales_tax_calls ||= 0 @sales_tax_calls += 1 price * 0.1025 end memoize :sales_tax end class Calculator extend Memoist include Rates attr_reader :fib_calls def initialize @fib_calls = 0 end def fib(n) @fib_calls += 1 if n == 0 || n == 1 n else fib(n - 1) + fib(n - 2) end end memoize :fib def add_or_subtract(i, j, add) if add i + j else i - j end end memoize :add_or_subtract def counter @count ||= 0 @count += 1 end memoize :counter end class Book extend Memoist STATUSES = %w[new used].freeze CLASSIFICATION = %w[fiction nonfiction].freeze GENRES = %w[humor romance reference sci-fi classic philosophy].freeze attr_reader :title, :author def initialize(title, author) @title = title @author = author end def full_title "#{@title} by #{@author}" end memoize :full_title class << self extend Memoist def all_types STATUSES.product(CLASSIFICATION).product(GENRES).collect(&:flatten) end memoize :all_types end end class Abb extend Memoist def run(*_args) flush_cache if respond_to?(:flush_cache) execute end def execute some_method end def some_method # Override this end end class Bbb < Abb def some_method :foo end memoize :some_method end def setup @person = Person.new @calculator = Calculator.new @book = Book.new('My Life', "Brian 'Fudge' Turmuck") end def test_memoization assert_equal 'Josh', @person.name assert_equal 1, @person.name_calls 3.times { assert_equal 'Josh', @person.name } assert_equal 1, @person.name_calls end def test_memoize_with_optional_arguments assert_equal 4, @person.sleep(4) assert_equal 1, @person.sleep_calls 3.times { assert_equal 4, @person.sleep(4) } assert_equal 1, @person.sleep_calls 3.times { assert_equal 4, @person.sleep(4, :reload) } assert_equal 4, @person.sleep_calls end def test_memoize_with_options_hash assert_equal true, @person.update_attributes(age: 21, name: 'James') assert_equal 1, @person.update_attributes_calls 3.times { assert_equal true, @person.update_attributes(age: 21, name: 'James') } assert_equal 1, @person.update_attributes_calls 3.times { assert_equal true, @person.update_attributes({ age: 21, name: 'James' }, :reload) } assert_equal 4, @person.update_attributes_calls end def test_memoization_with_punctuation assert_equal true, @person.name? @person.memoize_all @person.unmemoize_all end def test_memoization_flush_with_punctuation assert_equal true, @person.name? @person.flush_cache(:name?) 3.times { assert_equal true, @person.name? } assert_equal 2, @person.name_query_calls end def test_memoization_with_nil_value assert_nil @person.age assert_equal 1, @person.age_calls 3.times { assert_nil @person.age } assert_equal 1, @person.age_calls end def test_reloadable assert_equal 1, @calculator.counter assert_equal 2, @calculator.counter(:reload) assert_equal 2, @calculator.counter assert_equal 3, @calculator.counter(true) assert_equal 3, @calculator.counter end def test_flush_cache assert_equal 1, @calculator.counter assert @calculator.instance_variable_get(:@_memoized_counter) @calculator.flush_cache(:counter) assert_equal false, @calculator.instance_variable_defined?(:@_memoized_counter) assert_equal 2, @calculator.counter end def test_class_flush_cache @book.memoize_all assert_equal "My Life by Brian 'Fudge' Turmuck", @book.full_title Book.memoize_all assert_instance_of Array, Book.instance_variable_get(:@_memoized_all_types) Book.flush_cache assert_equal false, Book.instance_variable_defined?(:@_memoized_all_types) end def test_class_flush_cache_preserves_instances @book.memoize_all Book.memoize_all assert_equal "My Life by Brian 'Fudge' Turmuck", @book.full_title Book.flush_cache assert_equal false, Book.instance_variable_defined?(:@_memoized_all_types) assert_equal "My Life by Brian 'Fudge' Turmuck", @book.full_title end def test_flush_cache_in_child_class x = Bbb.new # This should not throw error x.run end def test_unmemoize_all assert_equal 1, @calculator.counter assert_equal true, @calculator.instance_variable_defined?(:@_memoized_counter) assert @calculator.instance_variable_get(:@_memoized_counter) @calculator.unmemoize_all assert_equal false, @calculator.instance_variable_defined?(:@_memoized_counter) assert_equal 2, @calculator.counter end def test_all_memoized_structs # Person memoize :age, :is_developer?, :memoize_protected_test, :name, :name?, :sleep, :update, :update_attributes # Student < Person memoize :name, :identifier => :student # Teacher < Person memoize :seniority expected = %w[age is_developer? memoize_protected_test name name? sleep update update_attributes] structs = Person.all_memoized_structs assert_equal expected, structs.collect(&:memoized_method).collect(&:to_s).sort assert_equal '@_memoized_name', structs.detect { |s| s.memoized_method == :name }.ivar # Same expected methods structs = Student.all_memoized_structs assert_equal expected, structs.collect(&:memoized_method).collect(&:to_s).sort assert_equal '@_memoized_student_name', structs.detect { |s| s.memoized_method == :name }.ivar expected = (expected << 'seniority').sort structs = Teacher.all_memoized_structs assert_equal expected, structs.collect(&:memoized_method).collect(&:to_s).sort assert_equal '@_memoized_name', structs.detect { |s| s.memoized_method == :name }.ivar end def test_unmemoize_all_subclasses # Person memoize :age, :is_developer?, :memoize_protected_test, :name, :name?, :sleep, :update, :update_attributes # Student < Person memoize :name, :identifier => :student # Teacher < Person memoize :seniority teacher = Teacher.new assert_equal 'Josh', teacher.name assert_equal 'Josh', teacher.instance_variable_get(:@_memoized_name) assert_equal 'very_senior', teacher.seniority assert_equal 'very_senior', teacher.instance_variable_get(:@_memoized_seniority) teacher.unmemoize_all assert_equal false, teacher.instance_variable_defined?(:@_memoized_name) assert_equal false, teacher.instance_variable_defined?(:@_memoized_seniority) student = Student.new assert_equal 'Student Josh', student.name assert_equal 'Student Josh', student.instance_variable_get(:@_memoized_student_name) assert_equal false, student.instance_variable_defined?(:@_memoized_seniority) student.unmemoize_all assert_equal false, @calculator.instance_variable_defined?(:@_memoized_student_name) end def test_memoize_all @calculator.memoize_all assert_equal true, @calculator.instance_variable_defined?(:@_memoized_counter) end def test_memoize_all_subclasses # Person memoize :age, :is_developer?, :memoize_protected_test, :name, :name?, :sleep, :update, :update_attributes # Student < Person memoize :name, :identifier => :student # Teacher < Person memoize :seniority teacher = Teacher.new teacher.memoize_all assert_equal 'very_senior', teacher.instance_variable_get(:@_memoized_seniority) assert_equal 'Josh', teacher.instance_variable_get(:@_memoized_name) student = Student.new student.memoize_all assert_equal 'Student Josh', student.instance_variable_get(:@_memoized_student_name) assert_equal 'Student Josh', student.name assert_equal false, student.instance_variable_defined?(:@_memoized_seniority) end def test_memoization_cache_is_different_for_each_instance assert_equal 1, @calculator.counter assert_equal 2, @calculator.counter(:reload) assert_equal 1, Calculator.new.counter end def test_memoization_class_variables @book.memoize_all assert_equal "My Life by Brian 'Fudge' Turmuck", @book.instance_variable_get(:@_memoized_full_title) assert_equal "My Life by Brian 'Fudge' Turmuck", @book.full_title Book.memoize_all assert_instance_of Array, Book.instance_variable_get(:@_memoized_all_types) assert_equal 24, Book.all_types.count end def test_memoized_is_not_affected_by_freeze @person.freeze assert_equal 'Josh', @person.name assert_equal 'Joshua', @person.update('Joshua') end def test_memoization_with_args assert_equal 55, @calculator.fib(10) assert_equal 11, @calculator.fib_calls end def test_reloadable_with_args assert_equal 55, @calculator.fib(10) assert_equal 11, @calculator.fib_calls assert_equal 55, @calculator.fib(10, :reload) assert_equal 12, @calculator.fib_calls assert_equal 55, @calculator.fib(10, true) assert_equal 13, @calculator.fib_calls end def test_memoization_with_boolean_arg assert_equal 4, @calculator.add_or_subtract(2, 2, true) assert_equal 2, @calculator.add_or_subtract(4, 2, false) end def test_object_memoization [Company.new, Company.new, Company.new].each do |company| company.extend Memoist company.memoize :name assert_equal '37signals', company.name assert_equal 1, company.name_calls assert_equal '37signals', company.name assert_equal 1, company.name_calls end end def test_memoized_module_methods assert_equal 1.025, @calculator.sales_tax(10) assert_equal 1, @calculator.sales_tax_calls assert_equal 1.025, @calculator.sales_tax(10) assert_equal 1, @calculator.sales_tax_calls assert_equal 2.5625, @calculator.sales_tax(25) assert_equal 2, @calculator.sales_tax_calls end def test_object_memoized_module_methods company = Company.new company.extend(Rates) assert_equal 1.025, company.sales_tax(10) assert_equal 1, company.sales_tax_calls assert_equal 1.025, company.sales_tax(10) assert_equal 1, company.sales_tax_calls assert_equal 2.5625, company.sales_tax(25) assert_equal 2, company.sales_tax_calls end def test_double_memoization_with_identifier # Person memoize :age, :is_developer?, :memoize_protected_test, :name, :name?, :sleep, :update, :update_attributes # Student < Person memoize :name, :identifier => :student # Teacher < Person memoize :seniority Person.memoize :name, identifier: :again p = Person.new assert_equal 'Josh', p.name assert p.instance_variable_get(:@_memoized_again_name) # HACK: tl;dr: Don't memoize classes in test that are used elsewhere. # Calling Person.memoize :name, :identifier => :again pollutes Person # and descendents since we cache the memoized method structures. # This populates those structs, verifies Person is polluted, resets the # structs, cleans up cached memoized_methods Student.all_memoized_structs Person.all_memoized_structs Teacher.all_memoized_structs assert Person.memoized_methods.any? { |m| m.ivar == '@_memoized_again_name' } [Student, Teacher, Person].each(&:clear_structs) assert Person.memoized_methods.reject! { |m| m.ivar == '@_memoized_again_name' } assert_nil Student.memoized_methods.reject! { |m| m.ivar == '@_memoized_again_name' } assert_nil Teacher.memoized_methods.reject! { |m| m.ivar == '@_memoized_again_name' } end def test_memoization_with_a_subclass student = Student.new student.name student.name assert_equal 1, student.student_name_calls assert_equal 1, student.name_calls end def test_memoization_is_chainable klass = Class.new do def foo 'bar' end end klass.extend Memoist chainable = klass.memoize :foo assert_equal :foo, chainable end def test_protected_method_memoization person = Person.new assert_raises(NoMethodError) { person.memoize_protected_test } assert_equal 'protected', person.send(:memoize_protected_test) end def test_private_method_memoization person = Person.new assert_raises(NoMethodError) { person.is_developer? } assert_equal 'Yes', person.send(:is_developer?) assert_equal 1, person.is_developer_calls assert_equal 'Yes', person.send(:is_developer?) assert_equal 1, person.is_developer_calls end end memoist-0.16.0/.gitignore0000644000004100000410000000023213130050477015270 0ustar www-datawww-data*.gem *.rbc .bundle .config .yardoc Gemfile.lock InstalledFiles _yardoc coverage doc/ lib/bundler/man pkg rdoc spec/reports test/tmp test/version_tmp tmp memoist-0.16.0/README.md0000644000004100000410000000622113130050477014563 0ustar www-datawww-dataMemoist ============= [![Build Status](https://travis-ci.org/matthewrudy/memoist.svg?branch=master)](https://travis-ci.org/matthewrudy/memoist) [![ghit.me](https://ghit.me/badge.svg?repo=matthewrudy/memoist)](https://ghit.me/repo/matthewrudy/memoist) Memoist is an extraction of ActiveSupport::Memoizable. Since June 2011 ActiveSupport::Memoizable has been deprecated. But I love it, and so I plan to keep it alive. Usage ----- Just extend with the Memoist module ```ruby require 'memoist' class Person extend Memoist def social_security decrypt_social_security end memoize :social_security end ``` And person.social_security will only be calculated once. Every memoized function (which initially was not accepting any arguments) has a ```(reload)``` argument you can pass in to bypass and reset the memoization: ```ruby def some_method Time.now end memoize :some_method ``` Calling ```some_method``` will be memoized, but calling ```some_method(true)``` will rememoize each time. You can even memoize method that takes arguments. ```ruby class Person def taxes_due(income) income * 0.40 end memoize :taxes_due end ``` This will only be calculated once per value of income. You can also memoize class methods. ```ruby class Person class << self extend Memoist def with_overdue_taxes # ... end memoize :with_overdue_taxes end end ``` When a sub-class overrides one of its parent's methods and you need to memoize both. Then you can use the `:identifier` parameter in order to help _Memoist_ distinguish between the two. ```ruby class Clock extend Memoist def now "The time now is #{Time.now.hour} o'clock and #{Time.now.min} minutes" end memoize :now end class AccurateClock < Clock extend Memoist def now "#{super} and #{Time.now.sec} seconds" end memoize :now, :identifier => :accurate_clock end ``` Reload ------ Each memoized function comes with a way to flush the existing value. ```ruby person.social_security # returns the memoized value person.social_security(true) # bypasses the memoized value and rememoizes it ``` This also works with a memoized method with arguments ```ruby person.taxes_due(100_000) # returns the memoized value person.taxes_due(100_000, true) # bypasses the memoized value and rememoizes it ``` If you want to flush the entire memoization cache for an object ```ruby person.flush_cache # returns an array of flushed memoized methods, e.g. ["social_security", "some_method"] ``` Authors =========== Everyone who contributed to it in the rails repository. * Joshua Peek * Tarmo Tänav * Jeremy Kemper * Eugene Pimenov * Xavier Noria * Niels Ganser * Carl Lerche & Yehuda Katz * jeem * Jay Pignata * Damien Mathieu * José Valim * Matthew Rudy Jacobs Contributing ============ 1. Fork it ( https://github.com/matthewrudy/memoist/fork ) 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create new Pull Request License ======= Released under the [MIT License](http://www.opensource.org/licenses/MIT), just as Ruby on Rails is.