Shane
Shane

Reputation: 5677

How to use acts_like_string? in ruby

http://api.rubyonrails.org/classes/String.html#method-i-acts_like_string-3F

I was going through the acts_like_string? in ruby, but could not find any examples on how to use. I tried out but no luck.

puts str.acts_like_string?

Upvotes: 3

Views: 347

Answers (1)

mdesantis
mdesantis

Reputation: 8517

These are the results of searching for acts_like_string in my gems folder, grep --recursive --context 2 acts_like_string $(gem environment gemdir):

activesupport-4.1.0.rc1/lib/active_support/core_ext/string/behavior.rb-class String
activesupport-4.1.0.rc1/lib/active_support/core_ext/string/behavior.rb-  # Enable more predictable duck-typing on String-like classes. See <tt>Object#acts_like?</tt>.
activesupport-4.1.0.rc1/lib/active_support/core_ext/string/behavior.rb:  def acts_like_string?
activesupport-4.1.0.rc1/lib/active_support/core_ext/string/behavior.rb-    true
activesupport-4.1.0.rc1/lib/active_support/core_ext/string/behavior.rb-  end
--
activesupport-4.1.0.rc1/lib/active_support/multibyte/chars.rb-      alias to_str wrapped_string
activesupport-4.1.0.rc1/lib/active_support/multibyte/chars.rb-
activesupport-4.1.0.rc1/lib/active_support/multibyte/chars.rb:      delegate :<=>, :=~, :acts_like_string?, :to => :wrapped_string
activesupport-4.1.0.rc1/lib/active_support/multibyte/chars.rb-
activesupport-4.1.0.rc1/lib/active_support/multibyte/chars.rb-      # Creates a new Chars instance by wrapping _string_.
--
mail-2.5.4/lib/mail/multibyte/chars.rb-
mail-2.5.4/lib/mail/multibyte/chars.rb-      # Enable more predictable duck-typing on String-like classes. See Object#acts_like?.
mail-2.5.4/lib/mail/multibyte/chars.rb:      def acts_like_string?
mail-2.5.4/lib/mail/multibyte/chars.rb-        true
mail-2.5.4/lib/mail/multibyte/chars.rb-      end

As you can see, acts_like_string? returns true for ActiveSupport::Multibyte::Chars. Which problem does it resolve?

Suppose you have to check if some object is a String: you would write something like object.is_a? String; but in this way you exclude classes which don't inherit by String but that can be accounted as strings, like f.e. ActiveSupport::Multibyte::Chars, which enhances some string methods and delegates every missing method to its @wrapped_string instance variable.

Instead of object.is_a? String you can use object.acts_like?(:string): this will work fine because ActiveSupport defines (comments of mine):

# Provides acts_like? for every Ruby object, so you can call it
# on everything without worrying about its presence
class Object
  def acts_like?(duck)
    respond_to? :"acts_like_#{duck}?"
  end
end

# Provides acts_like_string? for String and every class which inherits by String
class String
  def acts_like_string?
    # this actually could be false or nil or whatever,
    # since acts_like? checks only the method presence
    true
  end
end

# Provides acts_like_string? ActiveSupport::Multibyte::Chars, delegating it
# to @wrapped_string instance variable (which in turn defines it if it is
# a String)
class ActiveSupport::Multibyte::Chars
  delegate :<=>, :=~, :acts_like_string?, :to => :wrapped_string
end

This allows you to write for example:

gem 'activesupport'
require 'active_support/all'

def method_which_works_only_with_a_string_argument(argument)
  unless argument.acts_like? :string
    raise ArgumentError, 'argument must act like a string'
  end
  argument.capitalize
end

argument = ActiveSupport::Multibyte::Chars.new 'über'
method_which_works_only_with_a_string_argument argument
# => "Über"
method_which_works_only_with_a_string_argument 123
# => ArgumentError: argument must act like a string

F.e., ActiveRecord uses it inside values sanitization:

[...]
def quote_bound_value(value, c = connection, column = nil) #:nodoc:
  if column
    c.quote(value, column)
  elsif value.respond_to?(:map) && !value.acts_like?(:string)
    if value.respond_to?(:empty?) && value.empty?
      c.quote(nil)
    else
      value.map { |v| c.quote(v) }.join(',')
    end
  else
    c.quote(value)
  end
end
[...]

Upvotes: 2

Related Questions