Programming TextMate in Ruby. Problem with TextMate.go_to - ruby

I'm modding a TextMate bundle even though I'm a complete beginner at Ruby. The problem I'm trying to solve is the issue of moving the caret to a certain positition after the command has made its output.
Basically what happens is this:
I hit a key combo which triggers a command to filter through the document and inserts text at the relevant places, then exits with replacing the document with the new filtered text.
What I want to happen next is for the caret to move back to where it originally was. I was pretty happy when I found the TextMate.go_to function, but I can only get it partly to work. The function:
positionY = ENV['TM_LINE_NUMBER']
positionX = ENV['TM_LINE_INDEX']
...
TextMate.go_to :line => positionY, :column => positionX; #column no worky
I can get the caret to the right line, but the column parameter isn't working. I've tried shifting them about and even doing the function with just the column param, but no luck. I've also tried with a hard coded integer, but the positionX param prints the correct line index, so I doubt there's anything there.
This is the only documentation I've found on this method, but I took a look in the textmate.rb and to my untrained eyes it seems I'm using it properly.
I know this can be achieved by macros, but I want to avoid that if possible.
I also know that you can use markers if you choose "Insert as snippet" but then I'd have to clear the document first, and I haven't really figured out how to do this either without using the "Replace document" option.
Anyone?

Let's look at the source code of the bindings:
def go_to(options = {})
default_line = options.has_key?(:file) ? 1 : ENV['TM_LINE_NUMBER']
options = {:file => ENV['TM_FILEPATH'], :line => default_line, :column => 1}.merge(options)
if options[:file]
`open "txmt://open?url=file://#{e_url options[:file]}&line=#{options[:line]}&column=#{options[:column]}"`
else
`open "txmt://open?line=#{options[:line]}&column=#{options[:column]}"`
end
end
Rather hackishly, the binding sets up a txmt:// URL and calls open on it in the shell.
So the first thing to do would be constructing an open URL and typing it into Terminal/your browser to see if TextMate is respecting the column parameter. If that works then perhaps there is a bug in your version's implementation of Textmate.go_to.

Related

How to find out if a string includes a word stored in a variable

I am testing browser data via cucumber. I am looking through a list of links on a page, to determine which link I should click.
So let's say I have a list of dessert links and I wanted to find the one for apple sauce. I call a method that goes through the links and finds the one that has apple sauce after I pass the name apple sauce to it.
The string "apple sauce" is stored in #dessert and since #dessert will change often, I need to know if there is a way to find out if say "apple sauce" is stored in the variable #dessert.
when I do #dessert.text.include? "##dessert" i keep getting false. I need this to be true in order to make the decision to click it. When I evaluate #dessert by itself I have "apple sauce"...
How can I get rid of the quotes ( " ) so they are not evaluated? I think this is messing me up!
The standard way to test if a string has another string in it is to either use a regular expression, where you can describe patterns for "close enough" matches, or to search for a literal substring:
#dessert = "apple sauce;pears;walnuts"
#dessert.include?("apple sauce")
# => true
I'm not suer why your question has "##dessert" since that evaluates to a string exactly like that. "#{#dessert}" is probably what you were intending, where #{...} inlines a string value, but that's redundant since you're only testing against a singular variable with no other data. x and "#{x}" evaluate to equivalent strings if x is a string to begin with.
You seem to be comparing #dessert, an object with #dessert.text, an attribute of that object. Also, you are using a form of string interpolation that I, along with others here, would recommend avoiding.
Try
#dessert.text.include? "#{#dessert.text}"
and see if it returns true.
Here's an example where I went into a container and pulled all the links out to see click, be navigated to the page, and then assert that the page titles, url, and breadcrumbs all included the text within the link within the container. You could just add an if statement that will evaluate whether a link has certain text, and if it does, click it.
From lib file
def pull_text_and_href_from_continent_link
#continents.each do |continent|
find(".continents li.#{continent}").hover
page.should have_selector(".#{continent} .continent-wrapper", :visible => true)
page.all(:css, '.continents .continent-wrapper a').each do |nav_link|
#array.push(:text => nav_link.native.attribute("text"), :href => nav_link[:href])
end
end
end
From spec file (this is a suite not using cuke, but the code is still similar)
it "should have the right page title, url, and breadcrumbs" do
#array.each do |info|
if info[:text].include?('See all')
pp "Skipping the see all link for this container"
else
visit_page_logged_out(info[:href])
assert_correct_page_url info[:href]
assert_country_breadcrumbs remove_specials(info[:text])
assert_page_title info[:text]
end
end

What is the best way to get keyboard events (input without press 'enter') in a Ruby console application?

I've been looking for this answer in the internet for a while and have found other people asking the same thing, even here. So this post will be a presentation of my case and a response to the "solutions" that I have found.
I am such new in Ruby, but for learning purposes I decided to create a gem, here.
I am trying to implement a keyboard navigation to this program, that will allow the user use short-cuts to select what kind of request he want to see. And in the future, arrow navigations, etc.
My problem: I can't find a consistent way to get the keyboard events from the user's console with Ruby.
Solutions that I have tried:
Highline gem: Seems do not support this feature anymore. Anyway it uses the STDIN, keep reading.
STDIN.getch: I need to run it in a parallel loop, because at the same time that the user can use a short-cut, more data can be created and the program needs to show it. And well, I display formated text in the console, (Rails log). When this loop is running, my text lost the all the format.
Curses: Cool but I need to set position(x,y) to display my text every time? It will get confusing.
Here is where I am trying to do it.
You may note that I am using "stty -raw echo" (turns raw off) before show my text and "stty raw -echo" (turns raw on) after. That keeps my text formated.
But my key listener loop is not working. I mean, It works in sometimes but is not consistent. If a press a key twice it don't work anymore and sometimes it stops alone too.
Let me put one part of the code here:
def run
# Two loops run in parallel using Threads.
# stream_log loops like a normal stream in the file, but it also parser the text.
# break it into requests and store in #requests_queue.
# stream_parsed_log stream inside the #requests_queue and shows it in the screen.
#requests_queue = Queue.new
#all_requests = Array.new
# It's not working yet.
Thread.new { listen_keyboard }
Thread.new { stream_log }
stream_parsed_log
end
def listen_keyboard
# not finished
loop do
char = STDIN.getch
case char
when 'q'
puts "Exiting."
exit
when 'a'
#types_to_show = ['GET', 'POST', 'PUT', 'DELETE', 'ASSET']
requests_to_show = filter_to_show(#all_requests)
command = true
when 'p'
#types_to_show = ['POST']
requests_to_show = filter_to_show(#all_requests)
command = true
end
clear_screen if command
#requests_queue += requests_to_show if command
command = false
end
end
I need a light in my path, what should I do?
That one was my mistake.
It's just a logic error in another part of code that was running in another thread so the ruby don't shows the error by default. I used ruby -d and realized what was wrong. This mistake was messing my keyboard input.
So now it's fixed and I am using STDIN.getch with no problem.
I just turn the raw mode off before show any string. And everything is ok.
You can check here, or in the gem itself.
That's it.

Intermittant "Element is no longer attached to the DOM" errors using watir-webdriver

I am using Watir-webdriver 0.5.3. Before with versions circa 0.4.x this was never trouble:
while $browser.div(:class => /^expander$/).exists?
$browser.div(:class => /^expander$/).click; sleep 1.5
end
The click causes some javascript to execute that changes the class for the div that was clicked, expanding a treeview control. The objective of the script is to keep expanding nodes until there are none left unexpanded.
I am frequently getting "Element is no longer attached to the DOM" on the .exists? line, which is esp. troubling, because the reason I began using .exists? extensively was to avoid such errors that immediately crash the script in the first place.
visually I do observe the expansion almost right away after the .click, and if I pause things right there, Firebug does confirm that the div with only class='expander' had been replaced with a div in its place with class='expander hasChildren expanded', and only that div.
The error seems to be coming up from webdriver.
Has anyone else had this problem or recommend workarounds?
In an earlier question I needed to switch to the /^expander$/ form to match exactly that class exclusively, after the new watir-webdriver behavior changed.
What about this?
while $browser.div(:class => /^expander$/).exists?
count = $browser.divs(:class => 'expander hasChildren expanded').size
$browser.div(:class => /^expander$/).click
$browser.wait_until{$browser.div(:class => 'expander hasChildren expanded', :index => count).exists?}
end
The other approach I have used where actions are causing things to go away, is get a count, and then work by index, from the last item back towards the first, that way the 'next thing' you are addressing should still exist. That can be more reliable than always addressing 'first one' where your prior action just removed 'first one'. If expanding things opens up new 'expander' classes then you might have to do this in waves, where you end up expanding the first tier, then the second, etc till you see no more of them to expand. it might mean making a method to expand all currently visible expanders, then checking when it is done to see if there are any visible expanders, and if so, call the method again.
Try this one
Watir::Wait.until do
$browser.div(:class => /^expander$/).click
not $browser.div(:class => /^expander$/).exists?
end
Following Chuck's approach this code also first enumerates all candidates that need clicking to get expanded or whatever, and then in a one-line foreach loop, clicks them from the bottom of the page going up:
hitlist = $browser.divs(:class => /^expander$/) # put all candidates into an array
hitlist.to_a.reverse.each {|r| r.click; sleep 0.1} # loop in reverse
$browser.wait_until { $browser.divs(:class => /^expander$/).size < 1} # Wait until they're all AJAXed out of existence
Lines 1 & 2 could even be compacted to simply $browser.divs(:class => /^expander$/).to_a.reverse.each {|r| r.click; sleep 0.1} if you don't think the interim hitlist collection might be handy to have...but nevermind that.
Even though the code looks sound, my main concern here however is the very severe performance penalty using a regex locator like /^expander$/ apparently has...not something they tell you in the docs! Not something I faced pre 0.5.3 when standard, quoted class locators like :class => "expander" were exclusively matched.
Once or twice would be forgivable (in my case finding div(:class => /^expander$/) takes between 5-50 seconds in a <100kB html page each time) but I'm especially worried about line 3: who's to stay how many times the {boolean test block} gets executed to poll if the condition is finally met?

Filling a textform - String too small?

I currently have to do a job where I have to copy the code of a website into a textfield.
I'm using watir to do the browser handling. As far as I know, I can only fill the field using the set function, which means that I have to do something like
browser.text_field(:id => "text").set sitetext
With sitetext being the code of the website that I'm copying into it.
I've loaded the code from a file into an array before and then pushed it into the string (probably not the best choice, but easiest for me right now), using the following code.
contentArray=Array.new
inputFile=File.open("my-site.html")
inputFile.each{|line| contentArray<<line}
inputFile.close
Now when I execute the first command to fill in the text_field, it slowly types in all the letters (is there an easy way to speed this up?), but after 692 characters it stops in the middle of the sentence.
[I pasted the text that was entered into charcounter.com, that's how I know this number.]
Where is the problem? Is ruby giving my strings a limited size for some reason? Can I somehow lift this barrier?
Is there another way to fill the text_field?
Try the .value method
browser.text_field(:id => "text").value=(open('my-site.html') { |f| f.read })
OR
I'm thinking the misprinting of umlauts etc is something to do with the codepage settings on your machine and the file you're reading from. You might have to experiment going from one code page to another ... I'm guessing your source file is CP850 or perhaps even UTF-8 and I think you need western european to get umlauts... but being Australian I really have no idea =)
http://en.wikipedia.org/wiki/ISO_8859
e.g.
require 'iconv'
browser.text_field(:id => "text").value=(
Iconv.iconv('CP850', 'ISO-8859-1', open('my-site.html') { |f| f.read })
)

Unable to find method for detecting if element exists on a page

I'm very new to Watir.
I have a bit of Ruby/Watir code that is supposed to detect if an element, exists, and if so, click it, if not, click a different element. Both elements, show up, every time. Unfortunately nothing I've tried works.
if browser.contains_text("/media/images/icons/reviewertools/editreview.jpg")
then browser.image(:src => "/media/images/icons/reviewertools/editreview.jpg").click
else browser.image(:src => "/media/images/icons/reviewertools/savereview.jpg").click
end
This eventually fails with "Unable to locate element, using {:src=>"/media/images/icons/reviewertools/savereview.jpg"} (Watir::Exception::UnknownObjectException)"
It should have clicked /editreview.jpg, which was visible.
I have also tried:
if browser.image("/media/images/icons/reviewertools/savereview.jpg").exists
then browser.image(:src => "/media/images/icons/reviewertools/savereview.jpg").click
as well as:
if browser.image("/media/images/icons/reviewertools/savereview.jpg").exists?
Note that NONE of these cases detect the element, or failing to do that, execute the else clause.
Please, if you respond, provide specific code examples for your suggestions.
There are only methods "exist?" and "exists?". So "exist" won't work. Consult here.
Can you try to identify existence of a different element, such as a link. Does it work for you? There shouldn be no exception. Watir needs to return False in this case.
You need to use the same syntax with both the click and the exists? methods. This has also been pointed out by Kat and Chuck and Kinofrost.
if browser.image(:src => "/media/images/icons/reviewertools/editreview.jpg").exists?
then browser.image(:src => "/media/images/icons/reviewertools/editreview.jpg").click
else browser.image(:src => "/media/images/icons/reviewertools/savereview.jpg").click
end
I'd recommend checking the DOM to double check the src for your image matches what you're putting. Press F12 in IE8, or use whatever tool is relevant to your browser. You could try using IRB to connect to the browser and try and find the image.
If these fail then I'd try locating the image another way. If the image is in a form this can cause problems and you'll have to locate the form before the image.
Or try another way to locate it, just to make sure that it's possible.
browser.image(:index => 3).click
browser.image(:id => 'an_image').click
browser.div(:id => 'image_container').image(:index => 2).click
You can use this link to see what ways you can identify an image, and don't forget that you can use more than one identifier at a time, eg. (:class => /regexofaclass/, :index => 2)
There's nothing wrong with your code as it is (apart from the ? at the end of "exists", and the last line which doesn't contain what you're looking for).
Presuming that this thing really is an 'image' as defined by it's HTML tag, your attempt to identify if the object is there is failing because
you are not using the right method, in Ruby, methods that return a bool end in a question mark
it's not text,
and in the other attempt you provided only a 'what' and not a how, and still used the wrong method.
try this
if browser.image(:src, "/media/images/icons/reviewertools/savereview.jpg").exists?
then browser.image(:src, "/media/images/icons/reviewertools/savereview.jpg").click
Otherwise have a good look at the HTML, are you actually looking at a 'button' perhaps?

Resources