What's the difference between sending a string and sending a symbol to call a method dynamically, e.g., foo.public_send(:bar) vs foo.public_send('bar')? Is there a concrete difference in how these are handled?
If symbols are better, is it worth to do foo.public_send('bar'.to_sym) if for some reason you need to construct your method name as a string?
There is no difference between them, in fact, when passing a string it is converted to a symbol.
No need to convert it since that same conversion (e.g. 'bar'.to_sym) will be done if a string is provided.
From the docs:
Invokes the method identified by symbol, passing it any arguments
specified. Unlike send, #public_send calls public methods only. When
the method is identified by a string, the string is converted to a
symbol.
Related
I can't seem to find the documentation for this - when calling the Win32 API DnsQueryEx or DnsServiceBrowse, for async operation you pass in a callback of type DNS_QUERY_COMPLETION_ROUTINE. This callback receives a pointer PDNS_RECORD (the definition doesn't use PDNS_RECORDA or PDNS_RECORDW, just PDNS_RECORD). That structure has a field pName, which is documented as:
A pointer to a string that represents the domain name of the record set. This must be in the string format that corresponds to the function called, such as ANSI, Unicode, or UTF8.
But, those async functions don't have different variants for different encodings, and I'm not constructing this structure, the library is providing it. How do I know what encoding the pName field uses?
you note yourself
This must be in the string format that corresponds to the function
called, such as ANSI, Unicode, or UTF8.
the DnsQueryEx and DnsServiceBrowse take Unicode strings as input ( DNS_QUERY_REQUEST.QueryName and DNS_SERVICE_BROWSE_REQUEST.QueryName). so on output it also must use Unicode format. DNS_QUERY_RESULT.pQueryRecords point to DNS_RECORDW
Why is the Net::HTTPResponse attribute 'code' returning a string? Coming from other languages this doesn't make sense to me.
The value is not intended to be used for arithmetic or other similar operations. This is similar to why you would choose a character type column over a numeric type column in a database.
This works with the string methods well too. For example, if you want to check that it’s a 3XX error, you can do code.start_with?("3") rather than using < and > operators.
My vague understanding is that, with Ruby 2.2's frozen method on string or Ruby 2.3's frozen-string-literal: true pragma, a relevant frozen string literal is evaluated only once throughout program execution if and only if the string does not have interpolation. The following seems to illustrate this:
Not interpolated
#frozen-string-literal: true
5.times{p "".object_id}
Outputs (same object IDs):
70108065381260
70108065381260
70108065381260
70108065381260
70108065381260
Interpolated
#frozen-string-literal: true
5.times{p "#{}".object_id}
Outputs (different object IDs):
70108066220720
70108066220600
70108066220420
70108066220300
70108066220180
What is this property (i.e., being evaluated only once) called? It should be distinct from immutability.
Is my understanding of the condition when strings come to have such property correct? Where is the official documentation mentioning this?
Is there a way to make an interpolated string be evaluated only once?
Interning. The strings are said to be interned.
Not completely. It is more like if the interpreter can decide what the value of the string would be before evaluating it. For example, consider:
5.times { puts "#{'foo'}".object_id }
The id is the same even though there is interpolation involved.
No. This is an internal optimization. The main point of Object#freeze is immutability.
UPDATE: Only literal strings get internalized. This is evident here.
I couldn't find the part of the code responsible for interpolation. So I'm not sure why "#{'foo'}" is considered a literal string. Note that wherever this translation occurs, it is on a lower parser level and happens way before any actual processing. This is evident by the fact that String#freeze is mapped to rb_str_freeze, which doesn't call opt_str_freeze.
"Frozen" is not about whether the string is evaluated more than once. It is, you are right, about mutability.
A string literal will be evaluated every time the line containing it is encountered.
The (only) way to make it be evaluated only once, is to put it in a line of source code that is only executed once, instead of in a loop. A string literal in a loop (or any other part of source code) will always be evaluated every time that line of source code is executed in program flow.
This is indeed a separate thing than whether it is frozen/immutable or not, once evaluated.
The accepted answer is kind of misleading. "It is more like if the interpreter can decide what the value of the string would be before evaluating it." Nope. Not at all. It needs to be evaluated. If the string is frozen, then once it IS evaluated, it will use the same location in memory and the same object/object_id (which are two ways of saying the same thing) as all other equivalent strings. But it's still being evaluated, with or without interpolation.
(Without interpolation, 'evaluation' of a string literal is very very quick. With simple interpolation it's usually pretty quick too. You can of course use interpolation to call out to an expensive method though, hypothetically).
Without interpolation, I wouldn't worry about it at all. With interpolation, if you think your interpolation is expensive enough you don't want to do it in a loop -- the only way to avoid it is not to do it in a loop, but create the string once outside the loop.
Ruby docs probably talk about "String literals" rather than "literal Strings". A "String literal" is any String created by bytes in source code (using '', "", %Q[], or any of the other ways of creating strings literals in source code in ruby). With or without interpolation.
So what kinds of Strings aren't created by String literals? Well, a string created by reading in bytes from a file or network for instance. Or a String created by taking an existing string and calling a method on it that returns a copy, like some_string.dup. "String literal" means a string created literally in source code, rather than by reading from external input. http://ruby-doc.org/core-2.1.1/doc/syntax/literals_rdoc.html
In Ruby is there any way that data added to a string with interpolation can terminate the string? For example something like:
"This remains#{\somekindofmagic} and this does not" # => "This remains"
I'm assuming not but I want to be sure that doing something like
something.send("#{untrusted_input}=", more_untrusted_input)
doesn't actually leave some way that the interpolated string could be terminated and used to send eval.
Not possible with input string data AFAIK. Ruby Strings can contain arbitrary binary data, there should be no magic combination of bytes that terminates a String early.
If you are worried about "injection" style attacks on Ruby strings, then this is generally not easy to achieve if input is in the form of external data that has been converted to a string (and your specific concern about having an eval triggered cannot occur). This style of attack relies on code that passes an input string into some other interpreter (e.g. SQL or JavaScript) without properly escaping language constructs.
However, if String parameters are coming in the form of Ruby objects from untrusted Ruby code in the same process, it is possible to add side-effects to them:
class BadString
def to_s
puts "Payload"
"I am innocent"
end
end
b = BadString.new
c = "Hello #{b}"
Payload
=> "Hello I am innocent"
Edit: Your example
something.send("#{untrusted_input}=", more_untrusted_input)
would still worry me slightly, if untrusted_input really is untrusted, you are relying heavily on the fact that there are no methods ending in = that you would be unhappy to have called. Sometimes new methods can be defined on core classes due to use of a framework or gem, and you may not know about them, or they may appear in later versions of a gem. Personally I would whitelist allowed method names for that reason, or use some other validation scheme on the incoming data, irrespective of how secure you feel against open-ended evals.
Strings in ruby are internally handled as an array of bytes on the heap and an integer that holds the length of the string. So while in C a NUL byte (\0) terminates a string, this can not happen in ruby.
More info on ruby string internals here: http://patshaughnessy.net/2012/1/4/never-create-ruby-strings-longer-than-23-characters (also includes why ruby strings longer than 23 bytes were slower in ruby 1.9).
Is it possible to split a symbol without first converting it to a string? For example, I've tried
:split_this.split("_")
and it only returns an error. I've looked through the Symbol class reference, but all the example use to_s to convert it to a string.
I know I can convert it to a string, split it, and convert the two substrings to symbols, but that just seems a bit cumbersome. Is there a more elegant way to do this?
Since Ruby 1.9 some string's features are added to the Symbol class but not this much.The best you can do, I think is:
:symbol_with_underscores.to_s.split('_').map(&:to_sym)
You could turn this into a Symbol method:
class Symbol
def split(separator)
to_s.split(separator).map(&:to_sym)
end
end
:symbol_with_underscores.split('_')
# => [:symbol, :with, :underscores]
Think about symbols as numbers. Because symbols are internally stored as int numbers. Therefore they don't have string related methods.