So in Rails 3.2, ActiveSupport::Memoizable has been deprecated.
The message reads:
DEPRECATION WARNING: ActiveSupport::Memoizable is deprecated and
will be removed in future releases,simply use Ruby memoization
pattern instead.
It refers to "Ruby memoization pattern" (singular) as if there's one pattern we should all know and refer to...
I presume they mean something like:
def my_method
#my_method ||= # ... go get the value
end
or
def my_method
return #my_method if defined?(#my_method)
#my_method = # ... go get the value
end
Is there something else I've missed?
Here is the commit (and subsequent discussion) where Memoizable was deprecated: https://github.com/rails/rails/commit/36253916b0b788d6ded56669d37c96ed05c92c5c
The author advocates the #foo ||= ... approach and points to this commit as an example for migration: https://github.com/rails/rails/commit/f2c0fb32c0dce7f8da0ce446e2d2f0cba5fd44b3.
Edit:
Note that I don't necessarily interpret this change as meaning that all instances of memoize can or should be replaced w/ this pattern. I read it as meaning that Memoizable is no longer needed/wanted in the Rails code itself. As the comments point out, Memoizable is much more than just a wrapper around #foo ||= .... If you need those features, go ahead and use Memoizable, you'll just have to get it from somewhere other than ActiveSupport (I'm guessing someone will fork a gem version, if they haven't already).
Another option is to use the Memoist gem:
Memoist on GitHub
Memoist on RubyGems
It is a direct extraction from ActiveSupport::Memoizable and can be used as a drop-in replacement. Just require 'memoist' and change
extend ActiveSupport::Memoizable
to
extend Memoist
Just an addition to the top answer, to memoize a class method use the following pattern:
class Foo
class << self
def bar
#bar ||= begin
# ...
end
end
end
end
Based upon the comments on the commit referenced above by avaynshtok, I’m going with this:
ActiveSupport::Deprecation.silence { extend ActiveSupport::Memoizable }
… because I figure I’ll know when Memoizable is ripped out of ActiveSupport from my RSpec suite dying right out of the starting gate.
Related
We often shorten a block using the & notation on a symbol like this:
some_array.group_by(&:foo)
Is there a similar way to shorten expressions like {|x| x}?
some_array.group_by{|x| x}
If there were a method Object#self that returns self, then we can do
some_array.group_by(&:self)
but unfortunately, there is no such method. In terms of the number of characters, it may be longer, but readability improves.
Yes. #itself was implemented in Ruby 2.2.0.
You can access the Ruby core team discussion about this feature here.
As an interesting analogue, the #ergo method has been proposed, which would yield the receiver to a given block.
If you haven't yet upgraded to Ruby 2.2.0, you may wish to backport #itself and/or define #ergo as follows:
class Object
def itself; self end
def ergo
fail ArgumentError, "Block expected!" unless block_given?
yield self
end
end
And then:
some_array.group_by &:itself
Well, there's no built-in as far as I know, but you can make a reusable identity block:
id = Proc.new {|x| x}
some_array.group_by(&id)
And then if you really wish this were a language feature:
class Object
def it
Proc.new {|x| x}
end
end
And then you can do:
some_array.group_by(&it)
wherever you like. This may void your warranty.
Yes! The method Kernel#itself was added in Ruby 2.2.0. This method simply returns the object it was called on, so you can write:
some_array.group_by(&:itself)
You can see the extensive discussion of this feature here: https://bugs.ruby-lang.org/issues/6373. The patch was submitted by Rafael França in message #53. You can see it in the official Ruby source by looking in object.c.
If you are using a version of Ruby older than 2.2.0, you can easily add Kernel#itself into your project by putting this code somewhere in your project and making sure it gets required:
module Kernel
def itself
self
end
end if !Kernel.instance_methods.include?(:itself)
However, monkey-patching a part of the Ruby core like that can be dangerous and I would not recommend it if you are making reusable code, like a gem. Instead I would recommend just making your own identity function, as suggested by user2246674:
module MyLibrary
IDENT = Proc.new { |x| x }
array.group_by(&IDENT)
end
Nokogiri is awesome. I can do things like #css('.bla') which will return the first matching element.
Right now we need to do some parsing of Ruby source code - finding all methods within a class etc. We're using the ruby_parser gem, but all it does is comb your source code and spit out S-expressions. Is there anything like Nokogiri for these S-expressions which can do things like "return S-expression for first method found named 'foo'"?
The only thing I can think of, is Adam Sanderson's SExpPath library.
Although I am accepting Jörg's answer because it is more complete, I ended up discovering something else which I ended up using. ruby_parser installs a dependent gem named sexp_processor (it is in this gem where the Sexp class is actually defined). If you view the class docs there are a few methods that will help with basic Ruby finders. Here's an example:
class Sexp
def name # convenience method
self.sexp_body.first
end
end
# Print out all instance methods within classes. Beware - if "code" sexp itself
# is a class, it will NOT be included!
code = RubyParser.new.parse(IO.read('/src/file'))
code.each_of_type(:class){ |klass|
klass.each_of_type(:defn){ |meth|
puts meth.name
}
}
I don't know anything about gem that you are looking for, but you can find all methods within a class using instance_methods:
class Foo
def bar
end
end
irb(main):005:0> Foo.instance_methods - Object.instance_methods
=> [:bar]
You could check the rubinius parser, it may help you to do what you want.
Trying to use an ill-conceived framework which collects a list of results from a passed-in block, effectively this:
def sigh(&block)
r = (1..3).collect do |i|
yield(i)
end
# do something with r
end
I want the block I pass in to filter the items, but to skip the collection iteration rather than adding nil to the results like next would (since the framework doesn't compact them.) What's a simple way other than patching the gem? I.e.,
sigh {|i| next unless i == 1 } # results in [1,nil,nil] rather than just [1]
The bad news is that you'll have to patch the gem. Having your code block called by the gem doesn't give your code any special powers to affect how the calling code processes the block's return values.
The good news is that patching the gem can usually be done with a "monkey patch," where your program reopens the gem's class or module and makes the change. In this made-up example, we'll show the class nested in a module, since many gems make use of nested classes and modules:
require 'somegem'
# Monkey patch to cause Somegem's do_something_cool method
# to ignore the SomethingBadHappened exception
module SomeGem
class SomeClass
alias_method :orig_do_something_cool, :do_something_cool
def do_something_cool
orig_do_something_cool
rescue SomethingBadHappened
end
end
end
There is no way to do what you are asking for. If you post more details on the framework you are using, though, someone here may be able to help you think of a different way to work around the problem.
You'll need to patch, like others said. If you want a collection of i which satisfy some condition, the best choice would to replace collect with find_all, and then you could use:
sigh { |i| i == 1 } #=> [1]
I want to truncate #inspect output in irb (a large output must be cropped to MAX_LEN).
Currently, I override :inspect, :to_s methods for all specific objects.
Is there are other solution?
change $stdout ?
other?
For a clean solution, gem install hirb. hirb pages irb's returned values if they get too long.
If you want to monkeypatch irb:
module IRB
class Irb
def output_value
#context.last_value.to_s.slice(0, MAX_LEN)
end
end
end
I don't recommend this because it's a hack and breaks any time gems like ap and hirb are required.
Instead of monkeypatching irb, I'd recommend trying ripl, an irb alternative that is meant to extended.
The above as a ripl plugin would be:
require 'ripl'
module Ripl::SlicedInspect
def format_result(result)
result_prompt + result.inspect.slice(MAX_LEN)
end
end
Ripl::Shell.send :include, Ripl::SlicedInspect
With this plugin, you could require it as needed or add to your ~/.riplrc if you want to always use it.
Your solution is good.
It involves no dark magic, which might make the code less understandable and error-prone.
If you're just in IRB - you could define a monkeypatch in irb itself and or load a file that monkeypatches inspect via 'load'. This way you keep it out of your core codebase but you still get the functionality you need w/o having to override inspect in every class you wish to inspect....
If it's because you have a nested hash or something that's hard to decipher, try awesome_print. You can make it the default output formatter in irb by placing the following in your .irbrc:
require 'ap'
module IRB
class Irb
def output_value
ap #context.last_value
end
end
end
This makes objects with lots of data easy to decipher in IRB.
Even if you don't use awesome_print, you can truncate output using this same technique so you don't have to override to_s in your code.
For rails 3.1.1+, place the code below in helpers/irb_helper.rb
module IRB
class Irb
MAX_LEN = 10000
def output_value
if (#context.inspect_last_value.length > MAX_LEN)
printf #context.return_format, "#{#context.inspect_last_value[0..MAX_LEN]} <- Truncated"
else
printf #context.return_format, #context.inspect_last_value
end
end
end
end
If you'd like to customize your output more, check irb's source at https://github.com/Ruby/Ruby/blob/trunk/lib/irb.rb
I sometimes modify the objects themselves (via a module called BoringInspect which I include into the relevant classes) so that exception messages are also manageable.
Shoes wraps it's own Ruby install, right?
I can't use Fiber which is a Ruby1.9 feature. And, I want to use a Fiber for creating a generator.
Here's my code (so you can make sure the problem isn't with my code):
class BrownianGenerator
def initialize
#x = 0
#fiber = Fiber.new do
loop do
#x = #x+rand;
Fiber.yield #x
end
end
end
def next; #fiber.resume end
def rewind; #x=0 end
end
and if I made a shoes app like this:
Shoes.app do
#b = BrownianGenerator.new
end
if I pull up the shoes console, I see the error:
uninitialized constant #<class:0xblah>::BrownianGenerator::Fiber
Since, it's saying Fiber is an uninitialized constant, either something is wrong with my code or this Ruby version doesn't know about the Fiber class - the latter should be the case.
I saw this question on determining the version of Ruby (which is 1.8 for my mac install), but I don't know how I would change the version.
Check out Green Shoes.
It's functionality is based off of _why's original implementation, but it's packaged as a Gem and built specifically for 1.9.
or you could use aman gupta's "poor man's fibers" or try doing ::Fiber
or what not.
GL!
-r
So I jumped into freenode #shoes and found out that the nightly build of shoes is using Ruby1.9. I haven't had time to try building it yet, but that should solve my problem.