cenouro
cenouro

Reputation: 735

Ruby chaining with bang

Is it possible to write this excerpt of code without using an assignment?

self.name = self.name.to_s.squeeze(' ').strip

I have tried using bang versions of the methods, but couldn't use very well since they return nil if the operation didn't perform any changes (instead of returning self).

Upvotes: 2

Views: 644

Answers (3)

Gary S. Weaver
Gary S. Weaver

Reputation: 8096

For a one-liner with no (Ruby) attributions and without tap:

a.name && (a.name.squeeze!(' ') || a.name).strip!

e.g.:

$ irb
2.1.1 :001 > class A
2.1.1 :002?>   def name=(name)
2.1.1 :003?>     puts "setting name=#{name.inspect}"
2.1.1 :004?>     @name = name
2.1.1 :005?>     end
2.1.1 :006?>   attr_reader :name
2.1.1 :007?>   end
 => nil 
2.1.1 :008 > a = A.new
 => #<A:0x007fdc909d6df8> 
2.1.1 :009 > a.name = '  and   she    was  '
setting name="  and   she    was  "
 => "  and   she    was  " 
2.1.1 :010 > a.name && (a.name.squeeze!(' ') || a.name).strip!
 => "and she was" 
2.1.1 :011 > a.name
 => "and she was" 
2.1.1 :012 > a.name = 'and   she    was'
setting name="and   she    was"
 => "and   she    was" 
2.1.1 :013 > a.name && (a.name.squeeze!(' ') || a.name).strip!
 => nil 
2.1.1 :014 > a.name = 'and she was '
setting name="and she was "
 => "and she was " 
2.1.1 :015 > a.name && (a.name.squeeze!(' ') || a.name).strip!
 => "and she was" 

Upvotes: 1

Chuck
Chuck

Reputation: 237010

You'd have to tap the whole thing. So it would be something like:

str.tap {|x| x.squeeze!(' ')}.tap(&:strip!)

This is not something I would generally recommend doing. Even if you have a dire need for mutation, the best code clarity comes from using the methods the way they were designed:

str.squeeze!(' ')
str.strip!

If this is inconvenient, consider whether you really need the mutation.

Upvotes: 5

Uri Agassi
Uri Agassi

Reputation: 37409

If you really want to avoid assignment you could do this:

self.name = 'This  is a    test  '

[['squeeze!', ' '], 'strip!'].each { |cmd| self.name.send(*cmd) }

self.name
# => "This is a test"

Upvotes: 2

Related Questions