Reputation: 83
So the basic setting is the following:
in app/services/SomeService/ABC.rb
class SomeService::ABC
FORBIDDEN_CHARS = {" " => "+", "'" => "%27", "/" => "%2F", ":" => "%3A", "&" => "%26"}
def my_function(input)
#now do something fancy with the input
var = .... #a String is created
var.to_linkable
# continue with something fancy
end
def to_linkable
FORBIDDEN_CHARS.each{|key,value| self.gsub!(key,value)}
end
end
This results in the error: undefined method `to_linkable' for "bla bla":String
However in this way it works:
def to_linkable(link)
FORBIDDEN_CHARS.each{|key,value| link.gsub!(key,value)}
end
but I have to call it with 'to_linkable(link)' instead of just putting 'link.to_linkable'. If I copy paste my code in the Terminal the first way, there is no errors when calling 'link.to_linkable'.
So my question is: How (and where?) do I properly create such a to_linkable method? I might want to use it later on so that's why I want it to be an easy to use method. Thanks very much :) And yes, I am a Ruby newbie, coming over from Matlab :D
Upvotes: 2
Views: 62
Reputation: 28285
First of all, don't reinvent the wheel. Use URI.escape
, instead of trying to manually define which characters to replace.
However, for the sake of learning, if we go with your implementation...
var
is a string. If you wish to call a method on the string, then it must be defined in the String
class. It is usually not advised to add methods to core classes like this, but the following would work:
class String
FORBIDDEN_LINK_CHARS = {" " => "+", ...}
def to_linkable
FORBIDDEN_LINK_CHARS.each{|key,value| self.gsub!(key,value)}
self
end
end
"hello world".to_linkable # => "hello+world"
Alternatively, if you don't want to extend the String
class, but still wish to call an instance method without passing the variable, then you need to somewhere set var
as an instance variable in the class. This may or may not be a good idea, depending on the structure of the class.
For example, the following works:
class SomeService::ABC
FORBIDDEN_CHARS = {" " => "+", ...}
def my_function(input)
@var = .... #a String is created
make_var_linkable
end
def make_var_linkable
FORBIDDEN_CHARS.each{|key,value| @var.gsub!(key,value)}
end
end
...However, going back to my original point, the actual implementation I'd recommend is neither of the above. Just do:
require 'uri'
class SomeService::ABC
def my_function(input)
var = URI.escape(....)
end
end
Upvotes: 3
Reputation: 114138
If you don't want to "pollute" the whole string class, you can extend
a specific string instance with a module:
module SomeService
FORBIDDEN_CHARS = {" " => "+", "'" => "%27", "/" => "%2F", ":" => "%3A", "&" => "%26"}
class ABC
def my_function(input)
# ...
var = # a String is created
var.extend(Linkable)
var.to_linkable
# ...
end
end
module Linkable
def to_linkable
FORBIDDEN_CHARS.each { |key, value| gsub!(key,value) }
end
end
end
Upvotes: 0
Reputation: 121000
Both answers given so far are using FORBIDDEN_LINK_CHARS.length
number of gsub
operations, which is not quite optimal.
module StringWithForbiddenChars
FORBIDDEN_LINK_CHARS = {" " => "+", ...}
def to_linkable
gsub Regexp.union(FORBIDDEN_LINK_CHARS.keys), FORBIDDEN_LINK_CHARS
end
def to_linkable!
self.tap do |s|
s.gsub! Regexp.union(FORBIDDEN_LINK_CHARS.keys), FORBIDDEN_LINK_CHARS
end
end
end
String.prepend StringWithForbiddenChars
# or to extend the specific instance of a string:
# (str = "hello world").extend(StringWithForbiddenChars)
"hello world".to_linkable
#⇒ "hello+world"
Upvotes: 2
Reputation: 3043
When you write class String; ...; end
inside another class you are creating new class instead of editing existing ruby core String
class. Basically it can be said like String::ABC != String
. So you should firstly define your new String method like this:
class String
FORBIDDEN_CHARS = {" " => "+", "'" => "%27", "/" => "%2F", ":" => "%3A", "&" => "%26"}
def to_linkable
FORBIDDEN_CHARS.each{ |key, value| self.gsub!(key,value) }
self
end
end
After that you can use this method in any place with string objects. For example in your SomeService
class
class SomeService
def my_function(input)
#now do something fancy with the input
var = "#{input} " #a String is created
var.to_linkable
# continue with something fancy
end
end
So in the end you can do this:
SomeService.new.my_function("': 123123&")
# =>"%27%3A+123123%26++++"
Upvotes: 1