Is there a trick to using phantomjs for javascript driven sites? - ruby

Trying to use phantomjs to get content created by javascript and having a little trouble. Does phantomjs execute javascript just like other browsers do? Hoping someone can help.
When trying to get the value I'm looking for in Chrome, it comes up. However the value from phantomjs is blank.
2.3.0 :001 > require 'watir'
=> true
2.3.0 :002 > c = Watir::Browser.new
=> #<Watir::Browser:0x4598f2f5193003a8 url="data:," title="">
2.3.0 :003 > p = Watir::Browser.new :phantomjs
=> #<Watir::Browser:0x..fc337930306e55a98 url="about:blank" title="">
2.3.0 :004 > c.goto("http://www.walgreens.com/store/c/as-seen-on-tv/ID=359457-tier3")
=> "http://www.walgreens.com/store/c/as-seen-on-tv/ID=359457-tier3"
2.3.0 :005 > p.goto(c.url)
=> "https://www.walgreens.com/store/c/as-seen-on-tv/ID=359457-tier3"
2.3.0 :006 > c.element(:xpath => ".//*[#class='wag-itemscounttxt']/strong").text
=> "103"
2.3.0 :007 > p.element(:xpath => ".//*[#class='wag-itemscounttxt']/strong").text
=> ""
As you can see the phantomjs value is not present.

Related

Encoding and decoding ruby symbols

I discovered this behavior of multi_json ruby gem:
2.1.0 :001 > require 'multi_json'
=> true
2.1.0 :002 > sym = :symbol
=> :symbol
2.1.0 :003 > sym.class
=> Symbol
2.1.0 :004 > res = MultiJson.load MultiJson.dump(sym)
=> "symbol"
2.1.0 :005 > res.class
=> String
Is this an appropriate way to store ruby symbols? Does JSON provide some way to distinguish :symbol from "string"?
Nope is the simple answer. Most of the time it only really matters for hashes and there's a cheat on hashes, symbolize_keys!. Bottom line is that JSON does not understand symbols, just strings.
Since you are using MultiJson, you can also ask MultiJson to do this for you...
MultiJson.load('{"abc":"def"}', :symbolize_keys => true)

Why does a fork in ruby 1.9.2 break memcached connections, but not in 1.8.7?

While upgrading a large project from 1.8.7 to 1.9.2, I have uncovered a bug that I am at a loss to explain. It appears the fork operation breaks a memcached connection, even when the memcached connection isn't used in the forked code. Here is an IRB session, in 1.9.2 showing the error, and in 1.8.7 showing no error. Can anyone explain why there is no ServerIsMarkedDead error in 1.8.7 but there is in 1.9.2?
MBPR:$ rvm list
rvm rubies
ruby-1.8.7-p370 [ i686 ]
=* ruby-1.9.2-p320 [ x86_64 ]
# => - current
# =* - current && default
# * - default
MBPR:$ irb
irb(main):001:0> require 'rubygems'
=> false
irb(main):002:0> require 'memcached'
=> true
irb(main):003:0> mc = Memcached.new("localhost:11211", :timeout => 1.0)
=> #<Memcached:0x007fc91082abc8 #struct=#<Rlibmemcached::MemcachedSt:0x007fc91082a948>, #options={:hash=>:fnv1_32, :no_block=>false, :noreply=>false, :distribution=>:consistent_ketama, :ketama_weighted=>true, :buffer_requests=>false, :cache_lookups=>true, :support_cas=>false, :tcp_nodelay=>false, :show_backtraces=>false, :retry_timeout=>30, :timeout=>1.0, :rcv_timeout=>1.0, :poll_timeout=>1.0, :connect_timeout=>4, :prefix_key=>"", :prefix_delimiter=>"", :hash_with_prefix_key=>true, :default_ttl=>604800, :default_weight=>8, :sort_hosts=>false, :auto_eject_hosts=>true, :server_failure_limit=>2, :verify_key=>true, :use_udp=>false, :binary_protocol=>false, :credentials=>nil, :experimental_features=>false, :exception_retry_limit=>5, :exceptions_to_retry=>[Memcached::ServerIsMarkedDead, Memcached::ATimeoutOccurred, Memcached::ConnectionBindFailure, Memcached::ConnectionFailure, Memcached::ConnectionSocketCreateFailure, Memcached::Failure, Memcached::MemoryAllocationFailure, Memcached::ReadFailure, Memcached::ServerEnd, Memcached::ServerError, Memcached::SystemError, Memcached::UnknownReadFailure, Memcached::WriteFailure, Memcached::SomeErrorsWereReported]}, #default_ttl=604800, #not_found=#<Memcached::NotFound: Memcached::NotFound>, #not_stored=#<Memcached::NotStored: Memcached::NotStored>>
irb(main):004:0> mc.set "foo", 1, 100
=> nil
irb(main):005:0> mc.get "foo"
=> 1
irb(main):006:0> pid1 = fork do
irb(main):007:1* end
=> 9682
irb(main):008:0> sleep 1
=> 1
irb(main):009:0> mc.get "foo"
Memcached::ServerIsMarkedDead: Key {"foo"=>"localhost:11211:8"}
from /Users/me/.rvm/gems/ruby-1.9.2-p320#global/gems/memcached-1.5.0/lib/memcached/memcached.rb:630:in `reraise'
from /Users/me/.rvm/gems/ruby-1.9.2-p320#global/gems/memcached-1.5.0/lib/memcached/memcached.rb:608:in `check_return_code'
from /Users/me/.rvm/gems/ruby-1.9.2-p320#global/gems/memcached-1.5.0/lib/memcached/memcached.rb:517:in `get'
from (irb):9
from /Users/me/.rvm/rubies/ruby-1.9.2-p320/bin/irb:12:in `<main>'
irb(main):010:0>
And in 1.8.7
MBPR:$ rvm use 1.8.7
Using /Users/me/.rvm/gems/ruby-1.8.7-p370
MBPR:$ irb
1.8.7 :001 > require 'rubygems'
=> true
1.8.7 :002 > require 'memcached'
=> true
1.8.7 :003 > mc = Memcached.new("localhost:11211", :timeout => 1.0)
=> #<Memcached:0x10fc65dd0 #not_stored=#<Memcached::NotStored: Memcached::NotStored>, #servers=["localhost:11211:8"], #not_found=#<Memcached::NotFound: Memcached::NotFound>, #default_ttl=604800, #struct=#<Rlibmemcached::MemcachedSt:0x10fc65808>, #options={:cache_lookups=>true, :retry_timeout=>30, :rcv_timeout=>1.0, :exception_retry_limit=>5, :show_backtraces=>false, :binary_protocol=>false, :hash_with_prefix_key=>true, :server_failure_limit=>2, :exceptions_to_retry=>[Memcached::ServerIsMarkedDead, Memcached::ATimeoutOccurred, Memcached::ConnectionBindFailure, Memcached::ConnectionFailure, Memcached::ConnectionSocketCreateFailure, Memcached::Failure, Memcached::MemoryAllocationFailure, Memcached::ReadFailure, Memcached::ServerError, Memcached::SystemError, Memcached::UnknownReadFailure, Memcached::WriteFailure], :no_block=>false, :distribution=>:consistent_ketama, :timeout=>1.0, :ketama_weighted=>true, :prefix_delimiter=>"", :auto_eject_hosts=>true, :support_cas=>false, :hash=>:fnv1_32, :buffer_requests=>false, :poll_timeout=>1.0, :default_ttl=>604800, :sort_hosts=>false, :verify_key=>true, :tcp_nodelay=>false, :connect_timeout=>4, :default_weight=>8, :credentials=>nil, :use_udp=>false}>
1.8.7 :004 > mc.set "foo", 1, 100
=> nil
1.8.7 :005 > mc.get "foo"
=> 1
1.8.7 :006 > pid1 = fork do
1.8.7 :007 > end
=> 9799
1.8.7 :008 > sleep 1
=> 1
1.8.7 :009 > mc.get "foo"
=> 1
1.8.7 :010 >
This is fundamental to the UNIX process model with respect to fork. Both programs are absolutely identical clones, and the only way to differentiate one from the other is the result of the fork call.
The clone will terminate any connections as the master would when the process completes. That this doesn't happen in one version of Ruby is probably a bug.
This is why forking before opening connections is probably a good idea, and forking after opening connections requires special handling.

gchart not working

Okay, I want to draw charts within Ruby, so I've found gem called Googlecharts. Here's the problem:
-> % irb
1.9.2-p320 :001 > require 'gchart'
=> true
1.9.2-p320 :002 > Gchart.line(:size => '200x200', :title => 'title', :bg => 'ffffff', :data => [10,20,30,50])
=> "http://chart.apis.google.com/chart?"
As you can see, there's no link. What's wrong?

How can I escape a Ruby symbol with quotes only if needed?

IRB and Rails console both have a nice way of outputting symbols that only quote-escapes them when necessary. Some examples:
1.9.3p194 :001 > "#test".to_sym
=> :#test
1.9.3p194 :002 > "#Test".to_sym
=> :#Test
1.9.3p194 :003 > "#123".to_sym
=> :"#123"
1.9.3p194 :004 > "##_test".to_sym
=> :##_test
1.9.3p194 :005 > "test?".to_sym
=> :test?
1.9.3p194 :006 > "test!".to_sym
=> :test!
1.9.3p194 :007 > "_test!".to_sym
=> :_test!
1.9.3p194 :008 > "_test?".to_sym
=> :_test?
1.9.3p194 :009 > "A!".to_sym
=> :"A!"
1.9.3p194 :010 > "#a!".to_sym
=> :"#a!"
How would you do this yourself, so that you could do:
puts "This is valid code: #{escape_symbol(some_symbol)}"
The easiest and best way to do this is via Symbol's inspect method:
1.9.3p194 :013 > puts "This is valid code: #{"#a!".to_sym.inspect}"
This is valid code: :"#a!"
=> nil
1.9.3p194 :014 > puts "This is valid code: #{"a!".to_sym.inspect}"
This is valid code: :a!
You could look at the sym_inspect(VALUE sym) method in string.c in Ruby 1.9.3 that does that, if you're curious.
So, even though you don't need another method to call inspect, this would be the simplest implementation:
def escape_symbol(sym)
sym.inspect
end
Here's my attempt at implementing with a few regexs, although I'd suggest using inspect instead if you can:
def escape_symbol(sym)
sym =~ /^[#a-zA-Z_]#?[a-zA-Z_0-9]*$/ || sym =~ /^[a-z_][a-zA-Z_0-9]*[?!]?$/ ? ":#{sym}" : ":\"#{sym.gsub(/"/, '\\"')}\""
end

replicate CSV.generate_line behaviour of ruby 1.8.7 in ruby 1.9.2

ruby 1.9 now uses fastercsv, but how do i replicate the generate_line behaviour of ruby 1.8.7 ?
ruby-1.8.7-p334 :010 > require 'csv'
=> true
ruby-1.8.7-p334 :010 > CSV.generate_line(["ab","cd"], "\t")
=> "ab\tcd"
ruby-1.9.2-p180 :002 > require 'csv'
=> true
ruby-1.9.2-p180 :007 > CSV.generate_line(["ab","cd"], :row_sep => ?\t)
=> "ab,cd\t"
Notice how \t is between the two array items in ruby 1.8.7 and at last in 1.9.2
You have to use col_sep instead. row_sep is the row separator:
CSV.generate_line(["ab","cd"], :col_sep => ?\t)
=> "ab\tcd\n"
or
CSV.generate_line(["ab","cd"], :col_sep => ?\t, :row_sep => '')
=> "ab\tcd"
You can find more details and additional options in the documentation.
CSV.generate_line(['a','b','c'],:col_sep=>"\t")

Resources