sqlite mode column and header on, in ruby script - ruby

You know certainly about .mode column & headers on, to show datas of a sqlite database. But how to obtain the same result wth in Ruby script?
For example, to add it to my own script:
begin
require 'sqlite3'
db = SQLite3::Database.open('test_albums.db')
db.execute("select * from albums where ecoute = 2") do |result|
puts result.join(' - ')
end
end
Very thanks!

You need to get the table info using pragma table_info(), e.g.:
begin
require 'sqlite3'
db = SQLite3::Database.open('test_albums.db')
columns = db.execute("pragma table_info(albums)")
puts (columns.map { |c| c[1] }).join(' - ')
db.execute("select * from albums where ecoute = 2") do |result|
puts result.join(' - ')
end
end

Related

sqlite3 .execute2 snagging in a ruby file

I have the following sqlite code as a standalone file. It works.
the schema is basic. foo.db table bar Id, Text, Value, Etc are my columns
#!/usr/bin/env ruby
require 'sqlite3'
puts "enter a number"
input = gets.chomp.to_i
begin
db = SQLite3::Database.open('foo.db')
find_data = db.execute2 "select * from bar where Value = #{input}"
find_data.each do |f|
puts "[%-8s] %-8s | %-8s" % [f[1], f[2], f[3]]
end
rescue SQLite::Exception => e
puts e
ensure
db.close if db
end
execute2 locates the line and find_data.each prints out.
However when I take the above snippet and place into a method in a larger program, I get `no such column: [input]"
In my method. I have condensed the code:
...
def find_info(info)
begin
db = SQLite3::Database.open('foo.db')
puts db.get_first_value "select SQLite_VERSION()"
return "create a directory first" unless File.exist?('foo.db')
#line below does not work at print_out below
print_out = db.execute2 "SELECT * FROM Bar WHERE Value=#{info}"
#but making the following changes works:
#info_in = info; print_out = db.execute2 "select * from BAR WHERE Value = :info_in", info_in
return "no match" unless print_out != nil
print_out.each do |line|
puts "[%-8s] %-8s | %-8s" % [line[1], line[2], line[3]]
end
rescue SQLite3::Exception => e
puts e
ensure
db.close if db
end
end
...
print 'enter text to search for'
info = gets.chomp.to_s
X.NewInstance.new; X.find_info(info)
My question: Why am I obligated to use a placeholder in print_out? I believe I should be able just throw in a variable as print_out = db.execute2 "select * from Bar WHERE Value=#{info}"
please help. I am dumbfounded.
(Also: there must be a way on SO to indent blocks of code most efficiently than hitting 4 spaces for each line of code...I spend more time formatting the code than I do typing the question...pls advise?)
String interpolation fails in this instance. Placeholders can be utilized.
print_out = db.execute2 "select * from BAR WHERE Value = :info", info
print_out.each do |p|
puts "%s %s %s" % [p[1],p[2],p[3]]
end

display postgres sql result using pg gem

How do I display the result set of a postgres query using the pg gem only ? I want it to be in tabular form like it is in pgAdmin GUI tool. The code below does not help. The documentation is not clear, so I am unable to figure another way out. Please help !
require 'pg'
conn = PGconn.connect("db.corp.com", 5432, '', '', "schema", "user", "pass")
sql = 'select * from tbl limit 2'
res = conn.exec(sql)
res.each do |row|
row.each do |column|
end
end
gem list -
pg (0.9.0.pre156 x86-mswin32)
ruby - 1.8.7
Steps -
1. Get list of column names in result set (type PGResult).
2. Iterate each row(hash) of result set.
3. For each row (hash key)/columns found in step 1, find the column values (hash value).
Then print results as csv. I dont think this is efficient, but it gets the job done.
require 'pg'
conn = PGconn.connect("db.corp.com", 5432, '', '', "schema", "user", "pass")
sql = 'select * from tbl limit 2'
res = conn.exec(sql)
rows_count = res.num_tuples
column_names = res.fields
col_header = column_names.join(', ')
puts col_header
for i in 0..rows_count-1
row_hash = res[i]
row_arr = []
column_names.each do |col|
row_arr << row_hash[col]
end
row = row_arr.join(', ')
puts row
end

Preparing and executing SQLite Statements in Ruby

I have been trying to puts some executed statements after I prepare them. The purpose of this is to sanitize my data inputs, which I have never done before. I followed the steps here, but I am not getting the result I want.
Here's what I have:
require 'sqlite3'
$db = SQLite3::Database.open "congress_poll_results.db"
def rep_pull(state)
pull = $db.prepare("SELECT name, location FROM congress_members WHERE location = ?")
pull.bind_param 1, state
puts pull.execute
end
rep_pull("MN")
=> #<SQLite3::ResultSet:0x2e69e00>
What I am expecting is a list of reps in MN, but instead I just get "SQLite3::ResultSet:0x2e69e00" thing.
What am I missing here? Thanks very much.
Try this
def rep_pull(state)
pull = $db.prepare("SELECT name, location FROM congress_members WHERE location = ?")
pull.bind_param 1, state
pull.execute do |row|
p row
end
end

Calling multiple methods on a CSV object

I have constructed an Event Manager class that performs parsing actions on a CSV file, and produces html letters using erb. It is part of a jumpstart labs tutorial
The program works fine, but I am unable to call multiple methods on an object without the earlier methods interfering with the later methods. As a result, I have opted to create multiple objects to call instance methods on, which seems like a clunky inelegant solution. Is there a better way to do this, where I can create a single new object and call methods on it?
Like so:
eventmg = EventManager.new("event_attendees.csv")
eventmg.print_valid_phone_numbers
eventmg_2 = EventManager.new("event_attendees.csv")
eventmg_2.print_zipcodes
eventmg_3 = EventManager.new("event_attendees.csv")
eventmg_3.time_targeter
eventmg_4 = EventManager.new("event_attendees.csv")
eventmg_4.day_of_week
eventmg_5 = EventManager.new("event_attendees.csv")
eventmg_5.create_thank_you_letters
The complete code is as follows
require 'csv'
require 'sunlight/congress'
require 'erb'
class EventManager
INVALID_PHONE_NUMBER = "0000000000"
Sunlight::Congress.api_key = "e179a6973728c4dd3fb1204283aaccb5"
def initialize(file_name, list_selections = [])
puts "EventManager Initialized."
#file = CSV.open(file_name, {:headers => true,
:header_converters => :symbol} )
#list_selections = list_selections
end
def clean_zipcode(zipcode)
zipcode.to_s.rjust(5,"0")[0..4]
end
def print_zipcodes
puts "Valid Participant Zipcodes"
#file.each do |line|
zipcode = clean_zipcode(line[:zipcode])
puts zipcode
end
end
def clean_phone(phone_number)
converted = phone_number.scan(/\d/).join('').split('')
if converted.count == 10
phone_number
elsif phone_number.to_s.length < 10
INVALID_PHONE_NUMBER
elsif phone_number.to_s.length == 11 && converted[0] == 1
phone_number.shift
phone_number.join('')
elsif phone_number.to_s.length == 11 && converted[0] != 1
INVALID_PHONE_NUMBER
else
phone_number.to_s.length > 11
INVALID_PHONE_NUMBER
end
end
def print_valid_phone_numbers
puts "Valid Participant Phone Numbers"
#file.each do |line|
clean_number = clean_phone(line[:homephone])
puts clean_number
end
end
def time_targeter
busy_times = Array.new(24) {0}
#file.each do |line|
registration = line[:regdate]
prepped_time = DateTime.strptime(registration, "%m/%d/%Y %H:%M")
prepped_time = prepped_time.hour.to_i
# inserts filtered hour into the array 'list_selections'
#list_selections << prepped_time
end
# tallies number of registrations for each hour
i = 0
while i < #list_selections.count
busy_times[#list_selections[i]] += 1
i+=1
end
# delivers a result showing the hour and the number of registrations
puts "Number of Registered Participants by Hour:"
busy_times.each_with_index {|counter, hours| puts "#{hours}\t#{counter}"}
end
def day_of_week
busy_day = Array.new(7) {0}
d_of_w = ["Monday:", "Tuesday:", "Wednesday:", "Thursday:", "Friday:", "Saturday:", "Sunday:"]
#file.each do |line|
registration = line[:regdate]
# you have to reformat date because of parser format
prepped_date = Date.strptime(registration, "%m/%d/%y")
prepped_date = prepped_date.wday
# adds filtered day of week into array 'list selections'
#list_selections << prepped_date
end
i = 0
while i < #list_selections.count
# i is minus one since days of week begin at '1' and arrays begin at '0'
busy_day[#list_selections[i-1]] += 1
i+=1
end
#busy_day.each_with_index {|counter, day| puts "#{day}\t#{counter}"}
prepared = d_of_w.zip(busy_day)
puts "Number of Registered Participants by Day of Week"
prepared.each{|date| puts date.join(" ")}
end
def legislators_by_zipcode(zipcode)
Sunlight::Congress::Legislator.by_zipcode(zipcode)
end
def save_thank_you_letters(id,form_letter)
Dir.mkdir("output") unless Dir.exists?("output")
filename = "output/thanks_#{id}.html"
File.open(filename,'w') do |file|
file.puts form_letter
end
end
def create_thank_you_letters
puts "Thank You Letters Available in Output Folder"
template_letter = File.read "form_letter.erb"
erb_template = ERB.new template_letter
#file.each do |line|
id = line[0]
name = line[:first_name]
zipcode = clean_zipcode(line[:zipcode])
legislators = legislators_by_zipcode(zipcode)
form_letter = erb_template.result(binding)
save_thank_you_letters(id,form_letter)
end
end
end
The reason you're experiencing this problem is because when you apply each to the result of CSV.open you're moving the file pointer each time. When you get to the end of the file with one of your methods, there is nothing for anyone else to read.
An alternative is to read the contents of the file into an instance variable at initialization with readlines. You'll get an array of arrays which you can operate on with each just as easily.
"Is there a better way to do this, where I can create a single new object and call methods on it?"
Probably. If your methods are interfering with one another, it means you're changing state within the manager, instead of working on local variables.
Sometimes, it's the right thing to do (e.g. Array#<<); sometimes not (e.g. Fixnum#+)... Seeing your method names, it probably isn't.
Nail the offenders down and adjust the code accordingly. (I only scanned your code, but those Array#<< calls on an instance variable, in particular, look fishy.)

ruby cgi wont return method calls, but will return parameters

my environment: ruby 1.9.3p392 (2013-02-22 revision 39386) [x86_64-linux]
The thing is, I can make ruby return the parameters sent over GET. but when i'm trying to use them as arguements to my methods in if/else, ruby wont return anything and I end up with a blank page.
ph and pm return correctly:
http://127.0.0.1/cgi-bin/test.rb?hostname=node00.abit.dk&macadd=23:14:41:51:63
returns:
node00.abit.dk 23:14:41:51:63
Connection to the database (MySQL) works fine
When I test the method newHostName it outputs correctly:
puts newHostName
returns (which is correct)
node25.abit.dk
the code:
#!/usr/bin/ruby
require 'cgi'
require 'sequel'
require 'socket'
require 'timeout'
DB = Sequel.connect(:adapter=>'mysql', :host=>'localhost', :database=>'nodes', :user=>'nodeuser', :password=>'...')
#cgi-part to work
#takes 2 parameters:
#hostname & macadd
cgi = CGI.new
puts cgi.header
p = cgi.params
ph = p['hostname']
pm = p['macadd']
def nodeLookup(hostnameargv)
hostname = DB[:basenode]
h = hostname[:hostname => hostnameargv]
h1 = h[:hostname]
h2 = h[:macadd]
ary = [h1, h2]
return ary
end
def lastHostName()
#TODO: replace with correct sequel-code and NOT raw SQL
DB.fetch("SELECT hostname FROM basenode ORDER BY id DESC LIMIT 1") do |row|
return row[:hostname]
end
end
def newHostName()
org = lastHostName
#Need this 'hack' to make ruby grep for the number
#nodename e.g 'node01.abit.dk'
var1 = org[4]
var2 = org[5]
var3 = var1 + var2
sum = var3.to_i + 1
#puts sum
sum = "node" + sum.to_s + ".abit.dk"
return sum
end
def insertNewNode(newhost, newmac)
newnode = DB[:basenode]
newnode.insert(:hostname => newhost, :macadd => newmac)
return "#{newnode.count}"
end
#puts ph
#puts pm
#puts newHostName
cgi.out() do
cgi.html do
begin
if ph == "node00.abit.dk"
puts newHostName
else
puts nodeLookup(ph)
end
end
end
end
I feel like im missing something here. Any help is very much appreciated!
//M00kaw
What about modify last lines of your code as followed? CGI HTML generation methods take a block and yield the return value of the block as their content. So you should make newHostName or nodeLookup(ph) as the return value of the block passed to cgi.html(), rather than puts sth, which prints the content to your terminal and return nil. That's why cgi.html() got an empty string (nil.to_s).
#puts newHostName
cgi.out() do
cgi.html do
if ph == "node00.abit.dk"
newHostName
else
nodeLookup(ph)
end
end
end
p.s. It's conventional to indent your ruby code with 2 spaces :-)

Resources