Forum: Ruby making a name like "Copy of...", "Copy 2 of..."

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
73c04e9ef9ca435c5b19a2e765ae6d20?d=identicon&s=25 Max Williams (max-williams)
on 2009-05-28 13:31
Here's a little ruby exercise - i'm a bit brain damaged today and can't
think of a nice way to do this.

I want a method where you pass a name as a string and it returns 'copy
of x' or 'copy 2 of x' eg

new_name("My Lesson")
  => "Copy of My Lesson"

new_name("Copy of My Lesson")
  => "Copy 2 of My Lesson"

new_name("Copy 10 of My Lesson")
 => "Copy 11 of My Lesson"

I can only come up with horrible looking solutions but i feel there's a
nice way to do it.  Anyone?

cheers
max
3afd3e5e05dc9310c89aa5762cc8dd1d?d=identicon&s=25 Tim Hunter (Guest)
on 2009-05-28 13:45
(Received via mailing list)
Max Williams wrote:
>   => "Copy 2 of My Lesson"
>
> new_name("Copy 10 of My Lesson")
>  => "Copy 11 of My Lesson"
>
> I can only come up with horrible looking solutions but i feel there's a
> nice way to do it.  Anyone?
>
> cheers
> max

Use a closure to keep track of how many copies you've made:

def copy(string)
   x = 0
   p = lambda do
     x += 1
     if x == 1
       "Copy of #{string}"
     else
       "Copy #{x} of #{string}"
     end
   end
   p
end

c = copy("My Lesson")

puts c.call
puts c.call
puts c.call
73c04e9ef9ca435c5b19a2e765ae6d20?d=identicon&s=25 Max Williams (max-williams)
on 2009-05-28 14:04
Tim Hunter wrote:
> Max Williams wrote:
>>   => "Copy 2 of My Lesson"
>>
>> new_name("Copy 10 of My Lesson")
>>  => "Copy 11 of My Lesson"
>>
>> I can only come up with horrible looking solutions but i feel there's a
>> nice way to do it.  Anyone?
>>
>> cheers
>> max
>
> Use a closure to keep track of how many copies you've made:
>
> def copy(string)
>    x = 0
>    p = lambda do
>      x += 1
>      if x == 1
>        "Copy of #{string}"
>      else
>        "Copy #{x} of #{string}"
>      end
>    end
>    p
> end
>
> c = copy("My Lesson")
>
> puts c.call
> puts c.call
> puts c.call

That method returns a proc though, rather than a string.  Wouldn't that
mean that every time i want to call it i have to assign it to a variable
and then call that variable?  Or am i being dumb?  here's my
hacky-feeling solution:

  def copied_name(source_name)
    if source_name.match /^Copy of/i
      new_name = source_name.gsub!(/^Copy of/i, "Copy 1 of")
    elsif source_name.match /^Copy \d+ of/i
      num = source_name.scan(/\d+/).first.to_i
      new_name = source_name.gsub!(/^Copy #{num} of/i, "Copy #{num+1}
of")
    else
      new_name = "Copy of " + source_name
    end
  end

>> s = "My Lesson"
=> "My Lesson"
>> copied_name(_)
=> "Copy of My Lesson"
>> copied_name(_)
=> "Copy 1 of My Lesson"
>> copied_name(_)
=> "Copy 2 of My Lesson"
8f6f95c4bd64d5f10dfddfdcd03c19d6?d=identicon&s=25 Rick Denatale (rdenatale)
on 2009-05-28 15:02
(Received via mailing list)
On Thu, May 28, 2009 at 8:04 AM, Max Williams
<toastkid.williams@gmail.com> wrote:
>>> s = "My Lesson"
> => "My Lesson"
>>> copied_name(_)
> => "Copy of My Lesson"
>>> copied_name(_)
> => "Copy 1 of My Lesson"
>>> copied_name(_)
> => "Copy 2 of My Lesson"
>

Well, taking that approach how about:

 def copied_name(source_name)
   case source_name
   when /^Copy of (.*)$/i
     "Copy 1 of #{$1}"
   when /^Copy (\d+) of (.*)$/i
     num = $1.to_i
     "Copy #{num+1} of #{$2}"
   else
     "Copy of #{source_name}"
   end
 end

 s = "My Lesson" # => "My Lesson"
 s = copied_name(s) # => "Copy of My Lesson"
 s = copied_name(s) # => "Copy 1 of My Lesson"
 s = copied_name(s) # => "Copy 2 of My Lesson"

However, since you used the i option on your regex maybe you wanted to
preserve the case of the "Copy of part" which this doesn't

 s = "copy of My Lesson" # => "copy of My Lesson"
 s = copied_name(s) # => "Copy 1 of My Lesson"
 s = copied_name(s) # => "Copy 2 of My Lesson"
 s = copied_name(s) # => "Copy 3 of My Lesson"

If so then this does:

 def copied_name(source_name) # !> method redefined; discarding old
copied_name
   case source_name
   when /^(Copy )(of .*)$/i
     "#{$1}1 #{$2}"
   when /^(Copy )(\d+)( of .*)$/i
     num = $2.to_i
     "#{$1}#{num+1}#{$3}"
   else
     "Copy of #{source_name}"
   end
 end

 s = "My Lesson" # => "My Lesson"
 s = copied_name(s) # => "Copy of My Lesson"
 s = copied_name(s) # => "Copy 1 of My Lesson"
 s = copied_name(s) # => "Copy 2 of My Lesson"

 s = "copy of My Lesson" # => "copy of My Lesson"
 s = copied_name(s) # => "copy 1 of My Lesson"
 s = copied_name(s) # => "copy 2 of My Lesson"
 s = copied_name(s) # => "copy 3 of My Lesson"



--
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale
73c04e9ef9ca435c5b19a2e765ae6d20?d=identicon&s=25 Max Williams (max-williams)
on 2009-05-28 15:12
>  def copied_name(source_name)
>    case source_name
>    when /^Copy of (.*)$/i
>      "Copy 1 of #{$1}"
>    when /^Copy (\d+) of (.*)$/i
>      num = $1.to_i
>      "Copy #{num+1} of #{$2}"
>    else
>      "Copy of #{source_name}"
>    end
>  end
>

I'll go with this one, thanks Rick!

max
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2009-05-28 18:05
A bit more compact:

  def copied_name(source_name)
    if source_name =~ /\ACopy (\d+ )?of (.*)\z/i
      "Copy #{($1||1).to_i+1} of #{$2}"
    else
      "Copy of #{source_name}"
    end
  end

You can simplify ($1||1) to just $1, if you don't mind starting at Copy
1 of... instead of Copy 2 of...
This topic is locked and can not be replied to.