Need help in debugging a tiny ruby script - ruby

I get the following error, when i run my script.
fetch_scores.rb:20:in `<main>': undefined local variable or method `__EVENTTARGET' for main:Object (NameError)
HereÅ› the script:
#fetch_scores.rb
require 'net/http'
require 'open-uri'
#define a constant named URL so if the results URL changes we don't
#need to replace a hardcoded URL everywhere.
URL = "http://www.nitt.edu/prm/nitreg/ShowRes.aspx"
#checking the count of arguments passed to the script.
#it is only taking one, so let's show the user how to use
#the script
if ARGV.length != 1
puts "Usage: fetch_scores.rb student_name"
else
roll_no = ARGV[0] #could drop the ARGV length check and add a default using ||
# or name = ARGV[0] || nikhil
end
params = {
__EVENTTARGET => "Dt1",
__EVENTARGUMENT => "",
__VIEWSTATE => "dDwtMTM3NzI1MDM3O3Q8O2w8aTwxPjs+O2w8dDw7bDxpPDE+O2k8Mj47aTw0Pjs+O2w8dDxwPHA8bDxWaXNpYmxlOz47bDxvPHQ+Oz4+Oz47bDxpPDE+O2k8Mz47PjtsPHQ8O2w8aTwwPjtpPDE+O2k8Mj47aTwzPjtpPDQ+O2k8NT47aTw2Pjs+O2w8dDw7bDxpPDA+Oz47bDx0PDtsPGk8MT47PjtsPHQ8cDxwPGw8VGV4dDs+O2w8VEhJUkQgU0VNRVNURVIgTUFTVEVSIE9GIENPTVBVVEVSIEFQUExJQ0FUSU9OUyBOT1YtMjAxMChSRUdVTEFSKTs+Pjs+Ozs+Oz4+Oz4+O3Q8O2w8aTwxPjs+O2w8dDw7bDxpPDE+Oz47bDx0PHA8cDxsPFRleHQ7PjtsPFNVREVFUCBBR0FSV0FMOz4+Oz47Oz47Pj47Pj47dDw7bDxpPDE+Oz47bDx0PDtsPGk8MT47PjtsPHQ8cDxwPGw8VGV4dDs+O2...xwPGw8VGV4dDs+O2w8MTk7Pj47Pjs7Pjs+Pjs+Pjt0PDtsPGk8MT47PjtsPHQ8O2w8aTwxPjs+O2w8dDxwPHA8bDxUZXh0Oz47bDwwOz4+Oz47Oz47Pj47Pj47Pj47dDxwPHA8bDxWaXNpYmxlOz47bDxvPGY+Oz4+Oz47Oz47Pj47dDw7bDxpPDk+O2k8MTE+Oz47bDx0PHA8cDxsPFRleHQ7VmlzaWJsZTs+O2w8U2VsZWN0IFNlc3Npb24gICA7bzx0Pjs+Pjs+Ozs+O3Q8dDxwPHA8bDxWaXNpYmxlOz47bDxvPHQ+Oz4+Oz47dDxpPDM+O0A8LSBTZWxlY3QgLTtOT1YtMjAxMChSRUdVTEFSKTtNQVktMjAxMVtSRUdVTEFSXTs+O0A8MDs2Mjs2Njs+PjtsPGk8MT47Pj47Oz47Pj47dDxwPHA8bDxUZXh0Oz47bDxcZTs+Pjs+Ozs+Oz4+Oz4+Oz53I0hrrJ9pq04wIekH/y79mq+lYQ==",
TextBox1 => roll_no,
Dt1 => 66
}
results = Net::HTTP.post_form( URL, params )
p results

__EVENTTARGET in the params hash is parsed as a variable and that variable was never defined. Try "__EVENTTARGET" => "Dt1".

Related

Ruby smart variables [duplicate]

What is the best way to write a function (or something DSLish) that will allow me to write this code in Ruby. How would I construct the function write_pair?
username = "tyndall"
write_pair username
# where write_pair username outputs
username: tyndall
Is it possible to do? Looking for the most simple way to do this.
Sure it is possible!
My solution tests the var by Object#object_id identity: http://codepad.org/V7TXRxmL
It's crippled in the binding passing style ...
Although it works just for local vars yet, it can be easily be made "universal" adding use of the other scope-variable-listing methods like instance_variables etc.
# the function must be defined in such a place
# ... so as to "catch" the binding of the vars ... cheesy
# otherwise we're kinda stuck with the extra param on the caller
#_binding = binding
def write_pair(p, b = #_binding)
eval("
local_variables.each do |v|
if eval(v.to_s + \".object_id\") == " + p.object_id.to_s + "
puts v.to_s + ': ' + \"" + p.to_s + "\"
end
end
" , b)
end
# if the binding is an issue just do here:
# write_pair = lambda { |p| write_pair(p, binding) }
# just some test vars to make sure it works
username1 = "tyndall"
username = "tyndall"
username3 = "tyndall"
# the result:
write_pair(username)
# username: tyndall
If it's possible for you to use a symbol instead of the variable name, you could do something like this:
def wp (s, &b)
puts "#{s} = #{eval(s.to_s, b.binding)}"
end
In use:
irb(main):001:0> def wp (s, &b)
irb(main):002:1> puts "#{s} = #{eval(s.to_s, b.binding)}"
irb(main):003:1> end
=> nil
irb(main):004:0> var = 3
=> 3
irb(main):005:0> wp(:var) {}
var = 3
Note that you must pass the empty block {} to the method or it cannot get the binding to evaluate the symbol.
You can't actually get a variable's name in Ruby. But you could do something like this:
data = {"username" => "tyndall"}
Or even,
username = "tyndall"
data = {"username", "password", "favorite_color"}
data.each { |param|
value = eval(param)
puts "#{param}: #{value}"
}
I made a vim macro for this:
" Inspect the variable on the current line (in Ruby)
autocmd FileType ruby nmap ,i ^"oy$Iputs "<esc>A: #{(<esc>"opA).inspect}"<esc>
Put the variable you'd like to inspect on a line by itself, then type ,i (comma then i) in normal mode. It turns this:
foo
into this:
puts "foo: #{(foo).inspect}"
This is nice because it doesn't have any external dependencies (e.g. you don't have to have a library loaded up to use it).
Building on previous answers relating to symbols & bindings ... if passing in the variable name as a symbol works for you (who doesn't love cutting out extra keystrokes?!), try this:
def wp(var_name_as_sym)
# gets caller binding, which contains caller's execution environment
parent_binding = RubyVM::DebugInspector.open{|i| i.frame_binding(2) }
# now puts the symbol as string + the symbol executed as a variable in the caller's binding
puts %Q~#{var_name_as_sym.to_s} = #{eval("#{var_name_as_sym.to_s}.inspect", parent_binding)}~
end
aa=1
bb='some bb string'
os = OpenStruct.new(z:26, y:25)
Console output:
> wp :aa
aa = 1
=> nil
> wp :bb
bb = "some bb string"
=> nil
> wp :os
os = #<OpenStruct z=26, y=25>
=> nil
Using ruby 2.2.2p95
(Credit to banister for getting binding of calling context)
This is a simple solution:
def write_pair(variable)
puts variable + eval(variable)
end
This is more readable:
def write_pair(variable)
puts 'A' * 100
puts variable + ': ' + eval(variable).inspect
puts 'Z' * 100
end
Invocation:
write_pair "variable"
def write_pair var, binding
puts "#{ var } = #{ eval(var, binding)}"
end
username = "tyndall"
write_pair "username", binding
This seems weird because binding is never defined, but it works. From Ruby: getting variable name:
The binding() method gives a Binding object which remembers the
context at the point the method was called. You then pass a binding
into eval(), and it evaluates the variable in that context.
Be sure to pass a string, not the variable.
# make use of dynamic scoping via methods and instance vars
#_binding = binding
def eval_debug(expr, binding = #_binding)
"#{expr} => #{eval(expr, binding)}"
end
# sample invocation:
x = 10
puts eval_debug "x"
puts eval_debug "x**x"

No implicit converson from nil to String

I am getting an error
ruby/2.1.0/open-uri.rb:36:in `open': no implicit conversion of nil into String (TypeError)
here #filename, #directory and #xmlFile all have String as class type if I print them.
But somehow still in eval_script the above error is thrown. I don't undertstand why?
def execute
...
#result = eval_script(#filename,#xmlFile,#directory)
end
def eval_script filename,xml,directory
proc = Proc.new{}
eval(File.read(filename),proc.binding, filename)
end
Edit:
1) execute method is my rails action controller method.
Script:
# encoding: UTF-8
require 'nokogiri'
require 'open-uri'
doc = Nokogiri::XML(open(ARGV.first))
path = ARGV[1]
print path
File.delete(path + "/testOut.txt") if File.exist?(path + "/testOut.txt")
file = File.open(path + "/testOut.txt", 'w')
doc.css('testcases').each { |node| file.write "#{node['name']}\n" if node.css('results[test="testOut"]').any? }
Well, there's your problem. Line 4 of your script is
doc = Nokogiri::XML(open(ARGV.first))
But there are no ARGV elements being passed, so you're trying to open nil
Since you have the binding available, just refer to the variables defined in the eval_script method.
doc = Nokogiri::XML(open(xml))

Logging into website using Mechanize to fill in form?

I am trying to log into a site using Mechanize.
The form I am trying to fill out is the only one for on the page and is called "admin-login". The user name field has a name of "un" and the password field has a name of "pw".
My error output is:
myserver:in `addProduct': undefined local variable or method `form_name' for main:Object (NameError) from login.rb:82:in `<main>'
My code is:
def addProduct
agent = Mechanize.new
page = agent.get( 'correctURL' )
correctURL_form = page.form( 'admin-login' )
form_name.un = 'username'
form_pass.pw = 'password'
page = agent.submit( form_name, form_pass, correctURL_form.buttons.first )
puts page.body
end
Am I missing something here? I was told that this was fairly easy to pick up but I am really struggling with the basics of Mechanize.
I'd use something more like:
admin_login = page.form( 'admin-login' )
form_name = 'username'
form_pass = 'password'
page = agent.submit( form_name, form_pass, admin_login.buttons.first )
You can't name a variable with a '.' in it:
form_name.un = 'username'
form_pass.pw = 'password'
Ruby will assume that you're talking about instances of some class, called form_name or form_pass, which have methods called un and pw respectively. And, since those aren't defined, Ruby complains.
Instead, use a simple variable name and Ruby will be happy.
Also, note that variable names like correctURL_form are not Ruby-like. We use snake_case names for instance variables.
Okay, I have gotten it to work. Here is my corrected code.
def addProduct
agent = Mechanize.new
page = agent.get( 'correctURL' )
correctURL_form = page.form( 'admin-login' )
correctURL_form.un = 'username'
correctURL_form.pw = 'password'
page = agent.submit( correctURL_form, correctURL_form.buttons.first )
puts page.body
end
This got the output of the success page. Thanks all for the help!

Ruby nomethoderror "each" for nil class

I have some code which returns the error and i cannot understand why. I am abit of a newbie with Ruby but feel I am getting there:
line 27: NoMethodError "each" for NilClass
The code I am using is below:
require 'rubygems'
require 'nokogiri'
require 'sqlite3'
FIELDS = [['cityselect', 'VARCHAR'],['match', 'VARCHAR'], ['num_phone', 'NUMERIC'], ['name', 'VARCHAR'],['address', 'VARCHAR'] ]
DIV_ID = "#dgrSearch"
FILE_O = File.open('hold-data/directory-tel.txt', 'w')
FILE_O.puts( FIELDS.map{|f| f[0]}.join("\t") )
DB_NAME = "hold-data/directory-tel.sqlite"
File.delete(DB_NAME) if File.exists?DB_NAME
DATAB = SQLite3:Database.new( DB_NAME )
TABLE = "records_telephone"
DB_INSERT_STATEMENT = "INSERT into #{TABLE} values
(#{FIELDS.map{'?'}.join(',')})"
DATAB.execute "CREATE TABLE #{TABLE}(#{FIELDS.map{|f| "`#{f[0]}` #{f[1]}"}.join(', ')});"
FIELDS.each do |fn|
DATAB.execute "CREATE INDEX #{fn[2]} ON #{TABLE}(#{fn[0]})" unless fn[2].nil?
end
Dir.glob("hold-data/pages/*.html").reject{|f| f =~ /All match/}.each do |fname|
meta_stuff = File.basename(fname, '.html').split('--')
page = Nokogiri::HTML(open(fname))
page.css("#{DIV_ID} tr")[1..-2].each do |tr| # this is line #27
data_tds = tr.css('td').map{ |td|
td.text.gsub(/[$,](?=\d)/, '').gsub(/\302\240|\s/, ' ').strip
}
row_data = meta_stuff + data_tds
FILE_O.puts( data_row.join("\t"))
DATAB.execute(DB_INSERT_STATEMENT, row_data)
end
end
FILE_O.close
Can anybody see what I have done wrong?
It would be useful next time if you tell us which line the error occurs on.
From the looks of it theres only 1 line here where the expression your calling each on might return nil:
page.css("#{DIV_ID} tr")[1..-2].each do
Remember the_array[1..-2] will return nil if the_array is empty.
So page.css("#{DIV_ID} tr") might return an empty array hence the error.
If this behavior is not expiected I would consider invesigating why this is happening OR maybe check whether the array is empty before calling [1..-2] on it (see below). Just a suggestion.
if page.css("#{DIV_ID} tr").empty?
#empty array
else
#not empty
end

Accepting Command-Line Arguments into a Ruby Script

I'm trying to use the following code to accept in a file as an argument in Terminal which will then be read and update the body variable with its contents. If the file is not passed in then I want to have the prompt where the user can enter their own body copy.
require 'posterous'
Posterous.config = {
'username' => 'name',
'password' => 'pass',
'api_token' => 'token'
}
include Posterous
#site = Site.primary
#GETS POST TITLE
puts "Post title: "
title = STDIN.gets.chomp()
if defined?(ARGV)
filename = ARGV.first
end
if (defined?(filename))
body = File.open(filename)
body = body.read()
else
puts "Post body: "
body = STDIN.gets.chomp()
end
puts body
When I run the program without passing in a file I get this returned:
Post title:
Hello
posterous.rb:21:in `initialize': can't convert nil into String (TypeError)
from posterous.rb:21:in `open'
from posterous.rb:21:in `'
I'm rather new to ruby and thus am not the best at it. I've tried swapping a lot of things around and changing things but to no avail. What am I doing wrong?
defined?(ARGV) won't return a boolean false, but rather "constant". Since that doesn't evaluate to false, filename gets defined as ARGV[0], which is nil.
>> ARGV
=> []
>> defined?(ARGV)
=> "constant"
?> ARGV.first
=> nil
Instead you might check the length of ARGV:
if ARGV.length > 0
filename = ARGV.first.chomp
end
From the docs:
defined? expression tests whether or not expression refers to anything recognizable (literal object, local variable that has been initialized, method name visible from the current scope, etc.). The return value is nil if the expression cannot be resolved. Otherwise, the return value provides information about the expression.
Michael gave you the basic answer to your question. A slightly more Rubyish way of doing that would be to use ARGF to do the reading; then the conditional is only needed to decide whether or not to print the prompt:
puts "Post title: "
title = gets.chomp
puts "Post body: " if ARGV.length == 0
body = ARGF.gets.chomp
puts body
..of course, if you don't need to anything else with body, you can skip storing the contents of the file(s) and just do
puts ARGF.gets.chomp

Resources