Word Automation using WIN32OLE - ruby

I am trying to insert an image (jpg) in to a word document and the Selection.InlineShapes.AddPicture does not seem to be supported by win32old or I am doing something wrong. Has anyone had any luck inserting images.

You can do this by calling the Document.InlineShapes.AddPicture() method.
The following example inserts an image into the active document, before the second sentence.
require 'win32ole'
word = WIN32OLE.connect('Word.Application')
doc = word.ActiveDocument
image = 'C:\MyImage.jpg'
range = doc.Sentences(2)
params = { 'FileName' => image, 'LinkToFile' => false,
'SaveWithDocument' => true, 'Range' => range }
pic = doc.InlineShapes.AddPicture( params )
Documentation on the AddPicture() method can be found here.
Additional details on automating Word with Ruby can be found here.
This is the answer by David Mullet and can be found here

Running on WinXP, Ruby 1.8.6, Word 2002/XP SP3, I recorded macros and translated them, as far as I could understand them, into this:
require 'win32ole'
begin
word = WIN32OLE::new('Word.Application') # create winole Object
doc = word.Documents.Add
word.Selection.InlineShapes.AddPicture "C:\\pictures\\some_picture.jpg", false, true
word.ChangeFileOpenDirectory "C:\\docs\\"
doc.SaveAs "doc_with_pic.doc"
word.Quit
rescue Exception => e
puts e
word.Quit
ensure
word.Quit unless word.nil?
end
It seems to work. Any use?

Related

Entering text into tinymce using webdriver, ruby and variables

I'm using webdriver and Ruby...
So I was able to write text into a tinymce field using the script below. However on the last line, driver.execute... I would like to change the static value 'bob' to be the value of the variable being passed, parValue. I've tried few modifications to the driver.execute_script line, but I continue to get errors. In other words, I don't know javascript and I am unable to find a way to do this.
I've tried replacing the code and use sendkeys, but that does not print anything to my tinymce box. Is there a way to use the value being passed in from parValue and replace 'bob'?
def enterValues(driver,parField,parValue)
tinymce_frame = driver.find_element(:id => parField)
driver.switch_to.default_content
driver.switch_to.frame(tinymce_frame)
editor_body = driver.find_element(:tag_name => 'body')
driver.execute_script("arguments[0].innerHTML = 'bob'", editor_body)
end
this seems kind of simple so I'm worried I might be misunderstanding but you could use ruby's string interpolation to replace bob with parvalue:
def enterValues(driver,parField,parValue)
tinymce_frame = driver.find_element(:id => parField)
driver.switch_to.default_content
driver.switch_to.frame(tinymce_frame)
editor_body = driver.find_element(:tag_name => 'body')
driver.execute_script("arguments[0].innerHTML = '#{parValue}'", editor_body)
end

How do I parse a page using Nokogiri?

I am trying to parse the URL shown in the doc variable below. My issue is with the job variable. When I return it, it returns every job title on the page instead of that specific job title for the given review. Does anyone have advice how to return the specific job title I'm referring to?
require 'nokogiri'
require 'open-uri'
# Perform a google search
doc = Nokogiri::HTML(open('http://www.glassdoor.com/Reviews/Microsoft-Reviews-E1651.htm'))
reviews = []
current_review = Hash.new
doc.css('.employerReview').each do |item|
pro = item.parent.css('p:nth-child(1) .notranslate').text
con = item.parent.css('p:nth-child(2) .notranslate').text
job = item.parent.css('.review-microdata-heading .i-occ').text
puts job
advice = item.parent.css('p:nth-child(3) .notranslate').text
current_review = {'pro' => pro, 'con' => con, 'advice' => advice}
reviews << current_review
end
Looks like item.parent is #MainCol in each case, in other words the entire column.
Changing item.parent.css to item.css should solve your problem.

How to parse a web page using Nokogiri in Ruby?

I am using Nokogiri to parse html. For the website shown, I am trying to create an array of hashes where each hash will contain the pros, cons, and advice sections for a given review shown on the site. I am having trouble doing this and was hoping for some advice here. When I return a certain element, I don't get the right content shown on the site. Any ideas?
require 'open-uri'
require 'nokogiri'
# Perform a google search
doc = Nokogiri::HTML(open('http://www.glassdoor.com/Reviews/Microsoft-Reviews-E1651.htm'))
reviews = []
current_review = Hash.new
doc.css('.employerReview').each do |item|
pro = item.parent.css('p:nth-child(1) .notranslate').text
con = item.parent.css('p:nth-child(2) .notranslate').text
advice = item.parent.css('p:nth-child(3) .notranslate').text
current_review = {'pro' => pro, 'con' => con, 'advice' => advice}
reviews << current_review
end
Try this instead:
reviews = []
doc.css('.employerReview').each do |item|
pro, con, advice = item.css('.description .notranslate text()').map(&:to_s)
reviews << {'pro' => pro, 'con' => con, 'advice' => advice}
end
It's also preferred with ruby to use symbol keys, so unless you need them to be strings, I'd do
reviews << { pro: pro, con: con, advice: advice }

Stripping out results from a website that doesn't have differing URLs

I'm trying to automate the process of searching for alternative telephone numbers using SayNoTo0870 . Every time one searches for an alternate number or name it brings up the '/companysearch.php' page.
Clearly this page has no reference, and in my mind you can't just link to this page.
What I'm hoping to do is use the code below, to automate the opening of a browser, searching of a name/number, stripping out the HTML and then providing the top 5 results. I've got the automation part down, but clearly when trying to save the webpage using Hpricot it only brings up the 'Sorry nothing can be found page' because I can't link directly to the search result page.
Here is my code thus far:
(I've removed comments to shorten it)
require 'rubygems'
require 'watir'
require 'hpricot'
require 'open-uri'
class OH870
def searchName(name)
browser = Watir::Browser.new
browser.goto 'http://www.saynoto0870.com/search.php'
browser.text_field(:name => 'search_name').set name
browser.button(:name => 'submit').click
end
def searchNumber(number)
browser = Watir::Browser.new
browser.goto 'http://www.saynoto0870.com/search.php'
browser.text_field(:name => 'number').set number
browser.button(:name => 'submit').click
end
def loadNew(website)
doc = Hpricot(open(website))
puts(doc)
end
def strip_tags
stripped = website.gsub( %r{</?[^>]+?>}, '' )
puts stripped
end
end # class
class Main < OH870
puts "What is the name of the place you want?"
website = 'http://www.saynoto0870.com/companysearch.php'
question = gets.chomp
whichNumber = OH870.new
whichNumber.searchName(question)
#result = OH870.new
#withoutTags = website.strip_tags
#result.loadNew(withoutTags)
end
Now I'm not sure whether there's a way of "asking watir to follow through to the companysearch.php page and dump the results without having to pass this page as a variable.
I wonder if anyone has any suggestions here?
With WATIR, minus the extraneous libraries, here's all it takes to accomplish what you've described (using the 'name' test case only). I've pulled it out of the function format since you already know how to do that, and this will be a clearer test case path.
require 'watir'
#browser = Watir::Browser.new :firefox #open a browser called #browser
#browser.goto "http://(your search page here)" #go to the search page
#browser.text_field(:name => 'name').value = "Awesome" #fill in the 'name' field
#browser.button(:name => 'submit').click #submit the form
If all goes well, we should now be looking at the search results. WATIR already knows it's on a new page - we don't have to specify a URL. In the case that the results are in a frame, we do need to access that frame before we can view its content. Let's pretend they're in a DIV element with an ID of "search_results":
results = #browser.div(:id => "search_results").text
resultsFrame = #browser.frame(:index => 1) #in the case of a frame
results = resultsFrame.div(id => "search_results).text
As you can see, you do not need to save the entire page to parse the results. They could be in table cells, they could be in a different div per line, or a new frame. All are easily accessible with WATIR to be stored in a variable, array, or immediately written to the console or log file.
#results = Array.new #create an Array to store our results
#browser.divs.each do |div| #for each div element on the page
if div.id == "search_results" #if the div ID equals "search_results"
#results << div.text #add it to our array named #results
end
end
Now, if you just wanted the top 5 there are many ways to access them.
#results[0] #first element
#results[0..4] #first 5 elements
I'd also suggest you look into a few programming principles like DRY (Don't Repeat Yourself). In your function definitions where you see that they share code, like opening the browser and visiting the same URL - you can consolidate those:
def search(how, what)
#browser = Watir::Browser.new :firefox
#browser.goto "(that search url again)"
#browser.text_field(:name => how).value = what
etc...
end
search("name", "Hilton")
search("number", "555555")
Since we know that the two available text_field names are "name" and "number", and those make good logical sense as a 'how', we can parameterize them and use a single function for both the Search by Name and Search by Number test cases. This is more efficient, as long as the test cases remain similar enough to be shared.

Using Open-URI to fetch XML and the best practice in case of problems with a remote url not returning/timing out?

Current code works as long as there is no remote error:
def get_name_from_remote_url
cstr = "http://someurl.com"
getresult = open(cstr, "UserAgent" => "Ruby-OpenURI").read
doc = Nokogiri::XML(getresult)
my_data = doc.xpath("/session/name").text
# => 'Fred' or 'Sam' etc
return my_data
end
But, what if the remote URL times out or returns nothing? How I detect that and return nil, for example?
And, does Open-URI give a way to define how long to wait before giving up? This method is called while a user is waiting for a response, so how do we set a max timeoput time before we give up and tell the user "sorry the remote server we tried to access is not available right now"?
Open-URI is convenient, but that ease of use means they're removing the access to a lot of the configuration details the other HTTP clients like Net::HTTP allow.
It depends on what version of Ruby you're using. For 1.8.7 you can use the Timeout module. From the docs:
require 'timeout'
begin
status = Timeout::timeout(5) {
getresult = open(cstr, "UserAgent" => "Ruby-OpenURI").read
}
rescue Timeout::Error => e
puts e.to_s
end
Then check the length of getresult to see if you got any content:
if (getresult.empty?)
puts "got nothing from url"
end
If you are using Ruby 1.9.2 you can add a :read_timeout => 10 option to the open() method.
Also, your code could be tightened up and made a bit more flexible. This will let you pass in a URL or default to the currently used URL. Also read Nokogiri's NodeSet docs to understand the difference between xpath, /, css and at, %, at_css, at_xpath:
def get_name_from_remote_url(cstr = 'http://someurl.com')
doc = Nokogiri::XML(open(cstr, 'UserAgent' => 'Ruby-OpenURI'))
# xpath returns a nodeset which has to be iterated over
# my_data = doc.xpath('/session/name').text # => 'Fred' or 'Sam' etc
# at returns a single node
doc.at('/session/name').text
end

Resources