Ruby Error: syntax error, unexpected tGVAR, expecting $end - ruby

I am getting Ruby Error: syntax error, unexpected tGVAR, expecting $end.
I am using Mechanize to access a website and then I need to enter data into the form to search. When I pp page the site to get the form information I get:
#<Mechanize::Form
<name nil>
<method "POST">
<action "">
<fields
...
...
[text:0xb43f9c type: text name: ct100$MainContent$txtNumber value: ]
...
My code that is throwing this is:
Check_form = page.form()
Check_form.ct100$MainContent$txtNumber = 'J520518'
Any ideas on what is causing the error? Thank you in advance for the help!

Since this is not a valid variable or syntactically valid method name, you should use the alternate method to fetch or assign the values:
check_form = page.form
check_form['ct100$MainContent$txtNumber'] = 'J520518'
Variables are of the form #x for class instance variables, ##x for class variables, $x for global variables and x for plain variables, but in all cases the variable must consist of a letter or underscore followed by any number of letters, numbers, or underscores. $ cannot appear anywhere but the beginning, and when it does that means "global variable", something rarely used in most Ruby programming.

The error is telling you that there is a global variable where Ruby doesn't expect one. And there is: $txtNumber is a global variable, but it doesn't make sense for a global variable to appear at that place in your code.

Another way to make it legal would be
Check_form.send(:"ct100$MainContent$txtNumber=", 'J520518')

Related

How to have ruby conditionally check if variables exist in a string?

So I have a string from a rendered template that looks like
"Dear {{user_name}},\r\n\r\nThank you for your purchase. If you have any questions, we are happy to help.\r\n\r\n\r\n{{company_name}}\r\n{{company_phone_number}}\r\n"
All those variables like {{user_name}} are optional and do not need to be included but I want to check that if they are, they have {{ in front of the variable name. I am using liquid to parse and render the template and couldn't get it to catch if the user only uses 1 (or no) opening brackets. I was only able to catch the proper number of closing brackets. So I wrote a method to check that if these variables exist, they have the correct opening brackets. It only works, however, if all those variables are found.
here is my method:
def validate_opening_brackets?(template)
text = %w(user_name company_name company_phone_number)
text.all? do |variable|
next unless template.include? variable
template.include? "{{#{variable}"
end
end
It works, but only if all variables are present. If, for example, the template created by the user does not include user_name, then it will return false. I've also done this loop using each, and creating a variable outside of the block that I assign false if the conditions are not met. I would really, however, like to get this to work using the all? method, as I can just return a boolean and it's cleaner.
If the question is about how to rewrite the all? block to make it return true if all present variable names have two brackets before them and false otherwise then you could use something like this:
def validate_opening_brackets?(template)
variables = %w(user_name company_name company_phone_number)
variables.all? do |variable|
!template.include?(variable) || template.include?("{{#{variable}")
end
end
TL;DR
There are multiple ways to do this, but the easiest way I can think of is to simply prefix/postfix a regular expression with the escaped characters used by Mustache/Liquid, and using alternation to check for each of your variable names within the template variable characters (e.g. double curly braces). You can then use String#scan and then return a Boolean from Enumerable#any? based on the contents of the Array returned by from #scan.
This works with your posted example, but there may certainly be other use cases where you need a more complex solution. YMMV.
Example Code
This solution escapes the leading and trailing { and } characters to avoid having them treated as special characters, and then interpolates the variable names with | for alternation. It returns a Boolean depending on whether templated variables are found.
def template_string_has_interpolations? str
var_names = %w[user_name company_name company_phone_number]
regexp = /\{\{#{var_names.join ?|}\}\}/
str.scan(regexp).any?
end
Tested Examples
template_string_has_interpolations? "Dear {{user_name}},\r\n\r\nThank you for your purchase. If you have any questions, we are happy to help.\r\n\r\n\r\n{{company_name}}\r\n{{company_phone_number}}\r\n"
#=> true
template_string_has_interpolations? "Dear Customer,\r\n\r\nThank you for your purchase. If you have any questions, we are happy to help.\r\n\r\n\r\nCompany, Inc.\r\n(555) 555-5555\r\n"
#=> false

Is it possible to pass variable arguments to the include tag in Mako?

I have a mako template A that includes mako template B more than once. Mako template B expects certain arguments and I need to set them to different values on include.
In A.mak:
<%include
file="/components/B.mak"
args="lItems=some_variable, foo='bar'"
/>
<%include
file="/components/B.mak"
args="lItems=some_other_variable, foo='moooo'"
/>
In B.mak:
<%page args="lItems, foo"/>
%for dItem in lItems:
etc
Is this sort of thing even possible? I know it will work if I set lItems to 'some_value' and 'some_other_value' (ie: strings coded directly into A.mak) but I want to render A.mak with some_variable = [some,craze,list] and some_other_variable = [some,other,craze,list].
The code above gives me the error:
File ".../mako/runtime.py", line 202, in __str__
raise NameError("Undefined")
NameError: Undefined
I also tried doing the includes like so:
<%include
file="/components/B.mak"
args="lItems=${some_other_variable}, foo='moooo'"
/>
but that's a syntax error...
I tried it using a def also:
${the_B_def(foo='bar',lItems=some_variable)}
and got NameError: Undefined.
So my question is: How can I pass variables to templates 'within' a template?
You were almost there:
In A.mak:
<%include
file="/components/B.mak"
args="lItems=some_other_variable, foo='moooo'"
/>
In B.mak:
<%page args="lItems, foo"/>
%for dItem in lItems:
${foo}
%endfor

How to modify the value of a variable whose name is given

I wish to have a method that takes in a string, and then updates a variable with the name of that string. This is an example of my attempt:
#other_class = OtherClass.new()
def change_variable(variable_string)
self.#other_class.send.variable_string += 1
end
I am getting the error:
syntax error, unexpected tIVAR
with the pointer just before 'send' in the method above. Does anyone have any suggestions to make this work?
You probably want instance_variable_set http://ruby-doc.org/core-2.0/Object.html#method-i-instance_variable_set
The syntax using your variables is I think:
other_var = ('#' + variable_string).to_sym
#other_class.instance_variable_set( other_var, #other_class.instance_variable_get( other_var ) + 1 )
The immediate syntatic error is that you're using self and # wrongly.
Either one is fine but not in conjunction with each other.
So in your case self.other_class.send... would be fine but then you cant declare it as #.
As would # be but then you cant do self.
These are meant to do different things and these are that
# is an instance variable and so is self but the difference is that using # calls the attribute other_class directly as to where self calls the method other_class.
So # is both a getter and setter in one so you can do
#other_class = my_milk_man as to where
self.other_class -> self.other_class (as getter),
self.other_class = my_milk_man -> self.other_class= (as setter).

Rails String Interpolation in a string from a database

So here is my problem.
I want to retrieve a string stored in a model and at runtime change a part of it using a variable from the rails application. Here is an example:
I have a Message model, which I use to store several unique messages. So different users have the same message, but I want to be able to show their name in the middle of the message, e.g.,
"Hi #{user.name}, ...."
I tried to store exactly that in the database but it gets escaped before showing in the view or gets interpolated when storing in the database, via the rails console.
Thanks in advance.
I don't see a reason to define custom string helper functions. Ruby offers very nice formatting approaches, e.g.:
"Hello %s" % ['world']
or
"Hello %{subject}" % { subject: 'world' }
Both examples return "Hello world".
If you want
"Hi #{user.name}, ...."
in your database, use single quotes or escape the # with a backslash to keep Ruby from interpolating the #{} stuff right away:
s = 'Hi #{user.name}, ....'
s = "Hi \#{user.name}, ...."
Then, later when you want to do the interpolation you could, if you were daring or trusted yourself, use eval:
s = pull_the_string_from_the_database
msg = eval '"' + s + '"'
Note that you'll have to turn s into a double quoted string in order for the eval to work. This will work but it isn't the nicest approach and leaves you open to all sorts of strange and confusing errors; it should be okay as long as you (or other trusted people) are writing the strings.
I think you'd be better off with a simple micro-templating system, even something as simple as this:
def fill_in(template, data)
template.gsub(/\{\{(\w+)\}\}/) { data[$1.to_sym] }
end
#...
fill_in('Hi {{user_name}}, ....', :user_name => 'Pancakes')
You could use whatever delimiters you wanted of course, I went with {{...}} because I've been using Mustache.js and Handlebars.js lately. This naive implementation has issues (no in-template formatting options, no delimiter escaping, ...) but it might be enough. If your templates get more complicated then maybe String#% or ERB might work better.
one way I can think of doing this is to have templates stored for example:
"hi name"
then have a function in models that just replaces the template tags (name) with the passed arguments.
It can also be User who logged in.
Because this new function will be a part of model, you can use it like just another field of model from anywhere in rails, including the html.erb file.
Hope that helps, let me know if you need more description.
Adding another possible solution using Procs:
#String can be stored in the database
string = "->(user){ 'Hello ' + user.name}"
proc = eval(string)
proc.call(User.find(1)) #=> "Hello Bob"
gsub is very powerful in Ruby.
It takes a hash as a second argument so you can supply it with a whitelist of keys to replace like that:
template = <<~STR
Hello %{user_email}!
You have %{user_voices_count} votes!
Greetings from the system
STR
template.gsub(/%{.*?}/, {
"%{user_email}" => 'schmijos#example.com',
"%{user_voices_count}" => 5,
"%{release_distributable_total}" => 131,
"%{entitlement_value}" => 2,
})
Compared to ERB it's secure. And it doesn't complain about single % and unused or inexistent keys like string interpolation with %(sprintf) does.

What is Ruby doing with gsub here?

I'm working on converting code from Ruby to Node.js. I came across these lines at the end of a function and I'm curious what the original developers were trying to accomplish:
url = url.gsub "member_id", "member_id__hashed"
url = url.gsub member_id, member_id_hashed
url
I'm assuming that url at the end is Ruby's equivalent to return url;
as for the lines with gsub, from what I've found online that's the wrong syntax, right? Shouldn't it be:
url = url.gsub(var1, var2)?
If it is correct, why are they calling it twice, once with quotes and once without?
gsub does a global substitute on a string. If I had to guess, the URL might be in the form of
http://somewebsite.com?member_id=123
If so, the code has the following effect:
url.gsub "member_id", "member_id__hashed"
# => "http://somewebsite.com?member_id__hashed=123"
Assuming member_id = "123", and member_id_hashed is some hashed version of the id, then the second line would replace "123" with the hashed version.
url.gsub member_id, member_id_hashed
# => "http://somewebsite.com?member_id__hashed=abc"
So you're going from http://somewebsite.com?member_id=123 to http://somewebsite.com?member_id__hashed=abc
Documentation: https://ruby-doc.org/core-2.6/String.html#method-i-gsub
I'm assuming that the url at the end is Ruby's equivalent to return url;
If that code is part of a method or block, indeed, the line url is the value returned by the method. This is because by default a method in Ruby returns the value of the last expression that was evaluated in the method. The keyword return can be used (as in many other languages) to produce an early return of a method, with or without a return value.
that's the wrong syntax, right? shouldn't it be
url = url.gsub(var1, var2)?
The arguments used to invoke a method in Ruby may stay in parentheses but they may, as well, be listed after the method name, without parentheses.
Both:
url = url.gsub var1, var2
and
url = url.gsub(var1, var2)
are correct and they produce the same result.
The convention in Ruby is to not put parentheses around method arguments but this is not always possible. One such case is when one of the arguments is a call of another method with arguments.
The parentheses are then used to make everything clear both for the interpreter and the readers of the code.
If it is correct, why are they calling it twice, once with quotes and once without?
There are two calls of the same method, with different arguments:
url = url.gsub "member_id", "member_id__hashed"
The arguments of url.gsub are the literal strings "member_id" and "member_id__hashed".
url = url.gsub member_id, member_id_hashed
This time the arguments are the variables member_id and member_id_hashed.
This works the same in JavaScript and many other languages that use double quotes to enclose the string literals.
String#gsub is a method of class String that does search & replace in a string and returns a new string. It's name is short of "global substitute" (it replaces all occurrences). To replace only the first occurrence use String#sub.

Resources