21

Is there a way to simplify the following code?

filenames is a list of filenames (strings), e.g. ["foo.txt", "bar.c", "baz.yaml"]

filenames.map { |f| File.size(f) }

Is there any way to turn "File.size" into a proc or block? For methods on existing objects, I can do &:method. Is there something analogous for module level methods?

Arup Rakshit
  • 116,827
  • 30
  • 260
  • 317
Martin C. Martin
  • 3,565
  • 3
  • 29
  • 36

3 Answers3

33

You can use Object#method(method_name):

filenames.map(&File.method(:size))
tokland
  • 66,169
  • 13
  • 144
  • 170
5
filesize = proc { |f| File.size(f) }
filenames.map(&filesize)
Logan Serman
  • 29,447
  • 27
  • 102
  • 141
  • +1 Very cool. Why haven't I thought of doing this? Now I have a great new refactoring trick. – Mark Thomas Aug 15 '13 at 12:35
  • 4
    That doesn't simplify it, it adds extra complexity. – Martin C. Martin Aug 15 '13 at 13:51
  • 2
    @MartinC.Martin Indeed, it does not simplify it. But that is exactly what you asked. This answer turns the expression into a proc very simply. Blame yourself. It is your fault, not Logan's. – sawa Aug 15 '13 at 13:58
  • 1
    It doesn't simplify it in this case, but if you needed to re-use the proc it can help keep things DRY. Sometimes it also helps to give complex procs a name (through a local variable or method) to help keep your code readable when you don't care about the nitty gritty implementation of the proc. – Logan Serman Aug 15 '13 at 16:31
  • @MartinC.Martin fwiw, the two are subtly different in an important way. using `.method` like this returns a lambda, not just a proc. try this and you'll see what i mean: `%w{what a nice little doggo}.map(&String.new.method(:upcase))` – Alex Moore-Niemi Oct 02 '16 at 23:52
4

Stdlib's Pathname provides a more object oriented approach to files and directories. Maybe there's a way to refactor your filelist, e.g. instead of:

filenames = Dir.entries(".")
filenames.map { |f| File.size(f) }

you would use:

require 'pathname'
filenames = Pathname.new(".").entries
filenames.map(&:size)
Stefan
  • 109,145
  • 14
  • 143
  • 218