1

The following code works:

class String
  def color(code)
    "\e[#{code}m#{self}\e[0m"
  end
end

puts "Anything".color(93)

I want to be able to do:

puts "Anything".red

by catching the red as a string, and then giving it to a case-block as follows:

class String
  case **?WHAT?**       
  when "red" then color(91)
  else color(0)
  end
end

but it doesn't work. Is there a smart way to do this? How can I get the method name and use it in a case block?

sawa
  • 165,429
  • 45
  • 277
  • 381
yokmp
  • 145
  • 2
  • 10
  • 3
    You want a map of color names to codes, and a method missing to do the lookup. And hopefully no color names are the same as existing methods. You *could* also just define the color names you support and create explicit methods. – Dave Newton Jul 26 '15 at 22:46

2 Answers2

2

I think you're looking for method_missing and I've presented a solution below. This is great for learning, but you probably don't want to monkey patch String with method_missing if you're working on a production codebase!

class String
  def color(code)
    "\e[#{code}m#{self}\e[0m"
  end

  private

  def method_missing(name, *args)
    return send(:color, 91) if name == :red
    send(:color, 0)
  end
end

p "Anything".red # => "\e[91mAnything\e[0m" 
p "Anything".color(93) # => "\e[93mAnything\e[0m"
p "Anything".magenta # => "\e[0mAnything\e[0m"

Here is another way to solve the problem with define_method:

class String
  def self.color_mapping
    {
      red: 91,
      blue: 100
    }
  end

  def color(code)
    "\e[#{code}m#{self}\e[0m"
  end

  color_mapping.each do |c, v|
    define_method(c) do
      color(v)
    end
  end

  def method_missing(name, *args)
    send(:color, 0)
  end
end
Powers
  • 18,150
  • 10
  • 103
  • 108
0

Thanks for your effort. I've found a Solution based on your last code piece and a bit of asking here and there:

class String
  def color(code)
    "\e[#{code}m#{self}\e[0m"
  end

  colors = { black: 30, red: 31, green: 32, orange: 33, blue: 34, purple: 35, cyan: 36, gray: 37, white: 97,
             lgray: 90, lred: 91, lgreen: 92, yellow: 93, lblue: 94, lpurple: 95, lcyan: 96 }
  colors.each {|name, value| define_method(name) do; color(value); end; }

end

As you can see, I didn't catch the method's name but used a hash to create definitions via 'define_method'. Its much smaller code and nice to read than using case-blocks. :D

People told me to use a Module instead of patching core classes but for personal use its ok I think.

yokmp
  • 145
  • 2
  • 10