Encoding and decoding ruby symbols - ruby

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)

Related

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

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.

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.

Why was the object_id for true and nil changed in ruby2.0?

I came across this ruby object_id allocation question sometime back and then read this awesome article which talks about VALUE and explains why object_id of true, nil and false the way they are. I have been toying with ruby2.0 object_id when I found the apparent change that has been made regarding object_id of true and nil.
forbidden:~$ ruby -v
ruby 2.0.0p0 (2013-02-24 revision 39474) [x86_64-linux]
forbidden:~$
forbidden:~$ irb
irb(main):001:0> true.object_id
=> 20
irb(main):002:0> false.object_id
=> 0
irb(main):003:0> nil.object_id
=> 8
irb(main):004:0> exit
forbidden:~$
forbidden:~$ rvm use 1.9.3
Using /home/forbidden/.rvm/gems/ruby-1.9.3-p392
forbidden:~$ ruby -v
ruby 1.9.3p392 (2013-02-22 revision 39386) [x86_64-linux]
forbidden:~$
forbidden:~$ irb
irb(main):001:0> true.object_id
=> 2
irb(main):002:0> false.object_id
=> 0
irb(main):003:0> nil.object_id
=> 4
tl;dr: The values for true and nil were respectively 2, 4 in 1.9.3 and 1.8.7, but have been changed to 20, 8 in ruby2.0.0 - even though the id of false remains the same i.e. 0 and the ids for Fixnum maintains the same old 2n+1 pattern.
Also, the way Fixnum and Bignum are implemented is still the same in 2.0.0 as the example given in the above mentioned article also runs just the same way it used to:
irb(main):001:0>
irb(main):002:0* ((2**62)).class
=> Bignum
irb(main):003:0> ((2**62)-1).class
=> Fixnum
irb(main):004:0>
What's the reason behind this object_id change?
Why was this change made? How is this going to help developers?
A look at the Ruby source where these values are defined suggests that this has something to do with “flonums” (also see the commit where this was introduced). A search for ”flonum” came up with a message on the Ruby mailing list discussing it.
This is a technique for speeding up floating point calculations on 64 bit machines by using immediate values for some floating point vales, similar to using Fixnums for integers. The pattern for Flonums is ...xxxx xx10 (i.e. the last two bits are 10, where for fixnums the last bit is 1). The object_ids of other immediate values have been changed to accomodate this change.
You can see this change by looking at the object_ids of floats in Ruby 1.9.3 and 2.0.0.
In 1.9.3 different floats with the same value are different objects:
1.9.3p385 :001 > s = 10.234
=> 10.234
1.9.3p385 :002 > t = 10.234
=> 10.234
1.9.3p385 :003 > s.object_id
=> 2160496240
1.9.3p385 :004 > t.object_id
=> 2160508080
In 2.0.0 they are the same:
2.0.0p0 :001 > s = 10.234
=> 10.234
2.0.0p0 :002 > t = 10.234
=> 10.234
2.0.0p0 :003 > s.object_id
=> 82118635605473626
2.0.0p0 :004 > t.object_id
=> 82118635605473626

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