2

In Ruby we have methods like string.upcase which returns a new string and string.upcase! which modifies the string that called it.

I want to know how one goes about writing their own ! version of a method.

I am writing a method that searches for a string between two chars. I would like it to modify the string to equal the new string.

How does one accomplish this. (I have the method for finding the new string just need to know how to modify the caller)

ANSWER

class String
  def find_between(marker_one , marker_two)
    self[/#{Regexp.escape(marker_one)}(.*?)# {Regexp.escape(marker_two)}/m, 1]
  end

  def find_between!(marker_one , marker_two)
    self.replace(find_between(marker_one, marker_two))
  end
end

In the end self.replace was what was needed

3
  • I did, its not suitable for my needs. Commented Dec 2, 2016 at 11:47
  • 1
    Answers should be posted below Commented Dec 2, 2016 at 13:22
  • Welcome to Stack Overflow. I'd recommend reading "How to Ask". Answers don't belong in questions. SO isn't a discussion forum, it's like an online programming Q&A reference book; There's a single question (or closely related questions) and answers. Please remove the "answer" from the question, and, if you created the answer and intend for it to be the selected answer, add it below then wait for the system to let you select it. It's never necessary to show us what you wrote to fix the problem based on an answer given, instead select the answer that helped as the solution. Commented Dec 2, 2016 at 20:34

2 Answers 2

4

Just like a normal method:

def mathod_name!
  # whatever
end

The convention however is that you should add a bang alternative only if you have a "normal" version of the method with the same name and this version is somehow more "dangerous".

You can use String#[]= to modify a string in place.

Sign up to request clarification or add additional context in comments.

4 Comments

can you explain this more? String#[]= self[/#{Regexp.escape(marker_one)}(.*?)#{Regexp.escape(marker_two)}/m, 1] doesnt seem correct? Im not even sure where to search in the docs
ClassName#method_name is just the notation of "instance method named 'method_name' for the class 'ClassName'. So you should call the method above like this some_string[0..-1] = 'some other sting'
code shouldn't be #whatever. It should modify self, or be potentially dangerous.
"The bang sign means 'the bang version is more dangerous than its non bang counterpart; handle with care'" -- Matz ruby-forum.com/topic/176830#773946
3

This post is only for information, I strongly advise not to use it for real projects unless you are 100% sure what it may cause.

In case if you want to modify a String class to add new instance method use this

class String
  def cut!(start_pos, end_pos)
    # your magic
    self.replace(YOUR_NEW_STRING)
  end
end

Then you will be able to call it like this

x = "aaaabbbb"
x.cut! 1,4
puts x
=> "aaaa"

Modifying global objects is considered as a bad practice (aka "monkey patching"). But if someone needs to use it, then at least do it with refinements. This is the only valid use case for me so far.

4 Comments

you wouldn't even have to monkey patch String or use refinements to do this. You could create a new class that just delegates methods to a string stored in an instance variable.
@jphager2 could you please elaborate your point with a code example? I think I didn't get it
@jphager2, rather than provide a link to the example code, add an answer and note that it's to help explain. Even better, create a new question, explain the scenario, then add your code as the answer and wait for the system to let you select it as the answer. You can then add a link to it as a comment from the OPs question.
Good call for using refinements; Too few people use them.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.