All Projects → tycooon → Memery

tycooon / Memery

Licence: mit
A gem for memoization in Ruby

Programming Languages

ruby
36898 projects - #4 most used programming language

Projects that are alternatives of or similar to Memery

chimera
Lazy infinite compact streams with cache-friendly O(1) indexing and applications for memoization
Stars: ✭ 47 (-52.04%)
Mutual labels:  memoization
Verge
🟣 Verge is a very tunable state-management engine on iOS App (UIKit / SwiftUI) and built-in ORM.
Stars: ✭ 273 (+178.57%)
Mutual labels:  memoization
Immutable Tuple
Immutable finite list objects with constant-time equality testing (===) and no memory leaks.
Stars: ✭ 29 (-70.41%)
Mutual labels:  memoization
tacky
Primitive Object Memoization for Ruby
Stars: ✭ 14 (-85.71%)
Mutual labels:  memoization
cacheme-go
🚀 Schema based, typed Redis caching/memoize framework for Go
Stars: ✭ 19 (-80.61%)
Mutual labels:  memoization
Cachier
Persistent, stale-free, local and cross-machine caching for Python functions.
Stars: ✭ 359 (+266.33%)
Mutual labels:  memoization
maki
[beta] persistent memoization of computations, e.g. for repeatable tests and benchmarks
Stars: ✭ 16 (-83.67%)
Mutual labels:  memoization
React Selector Hooks
Collection of hook-based memoized selector factories for declarations outside of render.
Stars: ✭ 84 (-14.29%)
Mutual labels:  memoization
invokable
Objects are functions! Treat any Object or Class as a Proc (like Enumerable but for Procs).
Stars: ✭ 40 (-59.18%)
Mutual labels:  memoization
Re Reselect
Enhance Reselect selectors with deeper memoization and cache management.
Stars: ✭ 932 (+851.02%)
Mutual labels:  memoization
bash-cache
Transparent caching layer for bash functions; particularly useful for functions invoked as part of your prompt.
Stars: ✭ 45 (-54.08%)
Mutual labels:  memoization
redis-memolock
Redis MemoLock - Distributed Caching with Promises
Stars: ✭ 63 (-35.71%)
Mutual labels:  memoization
Cached
Rust cache structures and easy function memoization
Stars: ✭ 530 (+440.82%)
Mutual labels:  memoization
kashe
A memoization library based on weakmaps. 🤯 Sometimes cache is kashe
Stars: ✭ 60 (-38.78%)
Mutual labels:  memoization
Purefun
Functional Programming library for Java
Stars: ✭ 37 (-62.24%)
Mutual labels:  memoization
vector
A PHP functional programming library.
Stars: ✭ 19 (-80.61%)
Mutual labels:  memoization
Memoize State
The magic memoization for the State management. ✨🧠
Stars: ✭ 305 (+211.22%)
Mutual labels:  memoization
Beautiful React Redux
Redux 🚀, Redux 🤘, Redux 🔥 - and the magic optimization
Stars: ✭ 87 (-11.22%)
Mutual labels:  memoization
Decko
💨 The 3 most useful ES7 decorators: bind, debounce and memoize
Stars: ✭ 1,024 (+944.9%)
Mutual labels:  memoization
Moize
The consistently-fast, complete memoization solution for JS
Stars: ✭ 628 (+540.82%)
Mutual labels:  memoization

Memery   Gem Version Build Status Coverage Status

Memery is a Ruby gem for memoization of method return values. The normal memoization in Ruby doesn't require any gems and looks like this:

def user
  @user ||= User.find(some_id)
end

However, this approach doesn't work if calculated result can be nil or false or in case the method is using arguments. You will also require extra begin/end lines in case your method requires multiple lines:

def user
  @user ||= begin
    some_id = calculate_id
    klass = calculate_klass
    klass.find(some_id)
  end
end

For all these situations memoization gems (like this one) exist. The last example can be rewritten using memery like this:

memoize def user
  some_id = calculate_id
  klass = calculate_klass
  klass.find(some_id)
end

Installation

Simply add gem "memery" to your Gemfile.

Usage

class A
  include Memery

  memoize def call
    puts "calculating"
    42
  end

  # or:
  # def call
  #   ...
  # end
  # memoize :call
end

a = A.new
a.call # => 42
a.call # => 42
a.call # => 42
# Text will be printed only once.

a.call { 1 } # => 42
# Will print because passing a block disables memoization

Methods with arguments are supported and the memoization will be done based on arguments using an internal hash. So this will work as expected:

class A
  include Memery

  memoize def call(arg1, arg2)
    puts "calculating"
    arg1 + arg2
  end
end

a = A.new
a.call(1, 5) # => 6
a.call(2, 15) # => 17
a.call(1, 5) # => 6
# Text will be printed only twice, once per unique argument list.

For class methods:

class B
  class << self
    include Memery

    memoize def call
      puts "calculating"
      42
    end
  end
end

B.call # => 42
B.call # => 42
B.call # => 42
# Text will be printed only once.

For conditional memoization:

class A
  include Memery

  attr_accessor :environment

  def call
    puts "calculating"
    42
  end

  memoize :call, condition: -> { environment == 'production' }
end

a = A.new
a.environment = 'development'
a.call # => 42
# calculating
a.call # => 42
# calculating
a.call # => 42
# calculating
# Text will be printed every time because result of condition block is `false`.

a.environment = 'production'
a.call # => 42
# calculating
a.call # => 42
a.call # => 42
# Text will be printed only once because there is memoization
# with `true` result of condition block.

For memoization with time-to-live:

class A
  include Memery

  def call
    puts "calculating"
    42
  end

  memoize :call, ttl: 3 # seconds
end

a = A.new
a.call # => 42
# calculating
a.call # => 42
a.call # => 42
# Text will be printed again only after 3 seconds of time-to-live.
# 3 seconds later...
a.call # => 42
# calculating
a.call # => 42
a.call # => 42
# another 3 seconds later...
a.call # => 42
# calculating
a.call # => 42
a.call # => 42

Check if method is memoized:

class A
  include Memery

  memoize def call
    puts "calculating"
    42
  end

  def execute
    puts "non-memoized"
  end
end

a = A.new

a.memoized?(:call) # => true
a.memoized?(:execute) # => false

Difference with other gems

Memery is very similar to Memoist. The difference is that it doesn't override methods, instead it uses Ruby 2 Module.prepend feature. This approach is cleaner (for example you are able to inspect the original method body using method(:x).super_method.source) and it allows subclasses' methods to work properly: if you redefine a memoized method in a subclass, it's not memoized by default, but you can memoize it normally (without using awkward identifier: argument) and it will just work:

class A
  include Memery

  memoize def x(param)
    param
  end
end

class B < A
  memoize def x(param)
    super(2) * param
  end
end

b = B.new
b.x(1) # => 2
b.x(2) # => 4
b.x(3) # => 6

b.instance_variable_get(:@_memery_memoized_values)
# => {:x_70318201388120=>{[1]=>2, [2]=>4, [3]=>6}, :x_70318184636620=>{[2]=>2}}

Note how both method's return values are cached separately and don't interfere with each other.

The other key difference is that it doesn't change method's signature (no extra reload param). If you need to get unmemoized result of method, just create an unmemoized version like this:

memoize def users
  get_users
end

def get_users
  # ...
end

Alternatively, you can clear the whole instance's cache:

a.clear_memery_cache!

Finally, you can provide a block:

a.users {}

However, this solution is kind of hacky.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/tycooon/memery.

License

The gem is available as open source under the terms of the MIT License.

Author

Created by Yuri Smirnov.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].