How to avoid String Interpolation in Ruby returning unrendered variables? - ruby

I have table, in which cells are populated with data from a Ruby function call, which itself is a String Interpolation.
I want to take the first 5 characters of this string, and output it in the cell.
My problem is, is that what is outputted is not the result of the interpolation, but the variables itself.
Where am I going wrong here?
.slim table cell
td.event
== activity_cell.subtitle[1, 5]
activity_cell.rb
def subtitle
"#{fa_icon(icon1)} #{model_fa_icon} #{type_text} #{html_escape(extra_text)}"
end
output:
"#{fa
Note:
The string interpolation is rendered correctly if I'm not splitting the string to get the first X characters.

Related

The code always outputs "not"

The following code always outputs "not":
print "input a number please. "
TestNumber = gets
if TestNumber % 2 == 0
print "The number is even"
else
print "The number is not even"
end
What is going wrong with my code?
The gets() method returns an object of type String.
When you call %() on a String object, the return value is a new String object (usually it changes the text. You can read more about string formatting here).
Since there are no String objects that == 0, the if/else will always take the same path.
If you want to use the return value of gets() like a number, you will need to transform it into one first. The simplest approach is probably to use the to_i() method on String objects, which returns a new 'Integer' object. If you're doing something where the user input will not always be an integer (e.g. 3.14 or 1.5), you might need to use a different approach.
One last thing: in your example the result of gets() is saved into a constant called TestNumber. Constants are different to normal variables, and they will probably cause problems if you're not using them intentionally. Normal variables don't start with capital letters. (You can read more about ruby variables here). In ruby you need to write you variable names like this: test_number.
I suspect your Testnumber variable might be interpreted as a string during the operation. make sure the testnum is converted to an integer first even if you put in say 100 it could be its being interpreted as the stirng "100" and not the integer 100.
A similar issue can be found here: Ruby Modulo Division
You have to convert TestNumber from string to integer, as your input has linefeed and/or other unwanted characters that do not match an integer.
Use TestNumber = gets.to_i to convert to integer before testing.

In TI-BASIC, how do I add a variable in the middle of a String?

I am wondering how to make something where if X=5 and Y=2, then have it output something like
Hello 2 World 5.
In Java I would do
String a = "Hello " + Y + " World " + X;
System.out.println(a);
So how would I do that in TI-BASIC?
You have two issues to work out, concatenating strings and converting integers to a string representation.
String concatenation is very straightforward and utilizes the + operator. In your example:
"Hello " + "World"
Will yield the string "Hello World'.
Converting numbers to strings is not as easy in TI-BASIC, but a method for doing so compatible with the TI-83+/84+ series is available here. The following code and explanation are quoted from the linked page:
:"?
:For(X,1,1+log(N
:sub("0123456789",ipart(10fpart(N10^(-X)))+1,1)+Ans
:End
:sub(Ans,1,length(Ans)-1?Str1
With our number stored in N, we loop through each digit of N and store
the numeric character to our string that is at the matching position
in our substring. You access the individual digit in the number by
using iPart(10fPart(A/10^(X, and then locate where it is in the string
"0123456789". The reason you need to add 1 is so that it works with
the 0 digit.
In order to construct a string with all of the digits of the number, we first create a dummy string. This is what the "? is used
for. Each time through the For( loop, we concatenate the string from
before (which is still stored in the Ans variable) to the next numeric
character that is found in N. Using Ans allows us to not have to use
another string variable, since Ans can act like a string and it gets
updated accordingly, and Ans is also faster than a string variable.
By the time we are done with the For( loop, all of our numeric characters are put together in Ans. However, because we stored a dummy
character to the string initially, we now need to remove it, which we
do by getting the substring from the first character to the second to
last character of the string. Finally, we store the string to a more
permanent variable (in this case, Str1) for future use.
Once converted to a string, you can simply use the + operator to concatenate your string literals with the converted number strings.
You should also take a look at a similar Stack Overflow question which addresses a similar issue.
For this issue you can use the toString( function which was introduced in version 5.2.0. This function translates a number to a string which you can use to display numbers and strings together easily. It would end up like this:
Disp "Hello "+toString(Y)+" World "+toString(X)
If you know the length of "Hello" and "World," then you can simply use Output() because Disp creates a new line after every statement.

Complex requirements for string split around select commas

TL;DR
I need some help making a regex that will match any commas in a string that are side by side with unlimited white space around them and between them. The commas and their surrounding white space cannot be within matching single quotes or double quotes. I then need to capture the non-whitespace values from around those commas and count how many of those commas there are.
The values captured from around the commas will become their own values in the final array, while the commas that were counted will become nil values that are added to the final array.
Explanation of the problem:
This is a pretty complex problem so any help is greatly appreciated. I'm adding functionality to a library I've been using for a while now. I have this string that contains an array
"['d,og,f:asdf,:hello,",,\",,alsee',,,'ho,la', "-123,4,5.3", true, :good, false,,, "gr\'\'\'true,\',\'ee\"n", ":::testme", true]"
I would like to split this string only around select commas so that I have an array containing the following values
'd,og,f:asdf,:hello,",,\",,alsee'
nil
nil
'ho,la'
"-123,4,5.3"
true
:good
false
nil
nil
"gr\'\'\'true,\',\'ee\"n"
":::testme"
true
Then nil values are coming from the side by side commas that are not contained in any string. I wrote the following regex to split the string above (I already got rid of the start and end brackets):
/(?<=(?:['\"]|false|true|^|,)),(?=(?:\s*(?:(?::[\w]+)|(?:(?::?(?:\"[\s\S]*\")|(?:'[\s\S]*'))|(?:false|true)))\s*(?:,|$)))/
This splits the string so I get these values:
(0) "'d,og,f:asdf,:hello,",,\",,alsee',,"
(1) "'ho,la'"
(2) " "-123,4,5.3""
(3) " true"
(4) " :good, false,,"
(5) " "gr\'\'\'true,\',\'ee\"n""
(6) " ":::testme""
(7) " true"
All the values are strings as can be seen by their surrounding double quotes. They will not all end up that way though. A true or false will be converted to a boolean. The values surrounded by internal quotes will end up as strings. Then a value preceded with a : will end up as a symbol.
There are problems with the values at index 0 and 4. Index 0 should be this:
(0.0) "'d,og,f:asdf,:hello,",,\",,alsee'"
(0.1) nil
(0.2) nil
As you can see, the two commas at the end are gone. They have become the two nil values you see above. Then the string starts at the first single quote and ends at the last single quote, signifying that this value in the array is a string.
Then index 4 (" :good, false,,") should be this:
(4.0) " :good"
(4.1) " false"
(4.2) nil
(4.3) nil
The two commas at the end have become nil. Then " false" is it's own value which will later be converted to a boolean, while " :good" is also it's own value and will later be converted to a symbol.
To fix the problem with index 4 I have all the values run through a second regex. Here it is:
/^(\s*:(?:(?:[\w]+|\"[\s\S]+\"|'[\s\S]+')\s*)),([\s\S]*)$/
Instead of splitting this one I get the capture groups. It ends up returning this array for the value at index 4:
(4.0) " :good"
(4.1) " false,,"
That's what I wanted except for one problem. The value at index 4.1 (" false,,") has the two trailing commas which should be nil values in the array.
I need some help making a regex that will match any commas in a string that are side by side with unlimited white space around them and between them. The commas and their surrounding white space cannot be within matching single quotes or double quotes. I then need to capture the non-whitespace values from around those commas and count how many of those commas there are.
The values captured from around the commas will become their own values in the final array, while the commas that were counted will become nil values that are added to the final array.
"['d,og,f:asdf,:hello,"
,,\
",,alsee',,,'ho,la', "
-123,4,5.3
", true, :good, false,,, "
gr\
'\'
I count 4 strings. 3 in double quotes and the last one in single quotes?
You say this is broken down into smaller strings by your regx. But what about the characters outside the 4 strings?
Sorry, it looks a bit of a mess.
Try putting it all in a here document string and then breaking it down by a regx.
I finally figured it out myself. You can see how it fits in with the rest if you look at the description of the question above.
/^(([\s]*,)*)[\s]*((?::[\w]+)|(?::?(?:\"[\s\S]*\")|(?:'[\s\S]*')|false|true))?(([\s]*,)*)$/

string capture between duplicates in ruby

string = 'xabcdexfghijk'
In the example above, 'x' appears twice. I want to capture everything between the first 'x' and the next 'x'. Thus, the desired result is a new string that equals 'xabcdex'. Any ideas?
You could use a simple regular expression: /x.*?x/. This basically means "match any characters in between two x characters, as few times as possible (non-greedy)".
The matched text can be extracted with String#[regexp]
string = 'xabcdexfghijk'
string[/x.*?x/] # => "xabcdex"

What does this Ruby line say?

I am working with a custom renderer, and I used some copy paste from another site. I can't seem to figure out what this piece is doing right here.
"#{options[:callback]}(#{data})"
Here is the piece of code in full context.
ActionController.add_renderer :as3 do |data, options|
data = ActiveSupport::JSON.encode(data) unless data.respond_to?(:to_str)
data = "#{options[:callback]}(#{data})" unless options[:callback].blank?
self.content_type ||= Mime::JSON
self.response_body = data
end
It's simple string interpolation. It will produce a string like this, where callback is the value of options[:callback], and value is whatever is in the variable data.
"callback(value)"
In Ruby, double-quoted strings support interpolation via #{} syntax. That is, if you have a variable x containing the value 3, the string "The value of x is #{x}" will be evaluated to "The value of x is 3". Inside a #{} you can have any arbitrarily complex Ruby expression, including array/hash indexing. So, the first part of the string, "#{options[:callback]}" is simply substituting the value of options[:callback] into the string.
The next part, the () is simply raw string data, not executable code. Inside the (), you have a second #{} substitution of data. It might be clearer if you replace the two variable substituions with x and y:
x = 3
y = 4
"#{ x }(#{ y })"
The above will evaluate to the string "3(4)"
This is converting a JSON response to JSONP; imagine data is:
'{"some": "thing", "goes": "here"}'
JSONP states that the data should be wrapped in a JavaScript function call. So of options[:callback] is the string test (the name of the function to call), the resulting JSONP would be:
'test({"some": "thing", "goes": "here"})'
It's a template that replaces the first field with the value of options poiinted to by the interned string :callback, and the second field, inside the parens with the contents of data.
I'd bet a buck that the resulting string is going to be eval'd somewhere else, where it will become a call to a procedure. That would work something like this:
options[:callback] = "foo"
data="arg,arg,arg"
(Notice that data is being encoded into JSON, so the string passed as data is a json string.
The string then turns into "foo(arg.arg.arg)", and when it's eval'd it becomes a call to routine foo with those arguments.
http://www.ruby-doc.org/core-1.9.3/Kernel.html#method-i-eval
Update:
Actually, I take it back about the Ruby eval -- although that would work, it's more likely turning into a Javascript function call. This would then let you pass the name of a javascript function as a string and the code would return the appropriate callback function for execution by javascript later.
You can rewrite
"#{options[:callback]}(#{data})"
as
options[:callback].to_s + "(" + data.to_s + ")"

Resources