getting char from string as fixnum in 1.8 and 1.9

J

Joel VanderWerf

What's the best way to write this program so that it will run correctly
on both 1.8 and 1.9? This works, but I'm just curious if there's
anything better, preferably without the RUBY_VERSION test, without
adding methods to String, and without losing much efficiency compared
with 1.8's String#[].

if RUBY_VERSION =~ /\A1\.9/
def third_char_as_fixnum(s)
s[2].ord
end
else
def third_char_as_fixnum(s)
s[2]
end
end

s = "abc"
p third_char_as_fixnum(s) # ==> 99
 
D

David A. Black

Hi --

What's the best way to write this program so that it will run correctly on
both 1.8 and 1.9? This works, but I'm just curious if there's anything
better, preferably without the RUBY_VERSION test, without adding methods to
String, and without losing much efficiency compared with 1.8's String#[].

if RUBY_VERSION =~ /\A1\.9/
def third_char_as_fixnum(s)
s[2].ord
end
else
def third_char_as_fixnum(s)
s[2]
end
end

s = "abc"
p third_char_as_fixnum(s) # ==> 99

I'm sure someone will have something more elegant but I'll get the
ball rolling with:

def third_char_as_fixnum(s)
s[2,1].unpack("C*")[0]
end

It may not pass the not losing much efficiency test, though.


David

--
David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Now available: The Well-Grounded Rubyist (http://manning.com/black2)
Training! Intro to Ruby, with Black & Kastner, September 14-17
(More info: http://rubyurl.com/vmzN)
 
J

Joel VanderWerf

Joel said:
David said:
def third_char_as_fixnum(s)
s[2,1].unpack("C*")[0]
end

About a factor of three slower, as I measure it:

require 'benchmark'

if RUBY_VERSION =~ /\A1\.9/
def third_char_as_fixnum_1(s)
s[2].ord
end
else
def third_char_as_fixnum_1(s)
s[2]
end
end

def third_char_as_fixnum_2(s)
s[2,1].unpack("C").first
end

s = "abc"
N = 1_000_000

Benchmark.bmbm(12) do |bm|
bm.report("1") {N.times {third_char_as_fixnum_1(s)}}
bm.report("2") {N.times {third_char_as_fixnum_2(s)}}
end

__END__

Rehearsal -----------------------------------------------
1 1.060000 0.000000 1.060000 ( 1.079800)
2 1.620000 0.000000 1.620000 ( 1.634525)
-------------------------------------- total: 2.680000sec

user system total real
1 0.580000 0.000000 0.580000 ( 0.598929)
2 1.640000 0.000000 1.640000 ( 1.664318)
 
B

brabuhr

At said:
=A0What's the best way to write this program so that it will run correct= ly
=A0on both 1.8 and 1.9? This works, but I'm just curious if there's
=A0anything better, preferably without the RUBY_VERSION test, without
=A0adding methods to String, and without losing much efficiency compared
=A0with 1.8's String#[].

=A0if RUBY_VERSION =3D~ /\A1\.9/
=A0 =A0 def third_char_as_fixnum(s)
=A0 =A0 =A0 s[2].ord
=A0 =A0 end
=A0else
=A0 =A0 def third_char_as_fixnum(s)
=A0 =A0 =A0 s[2]
=A0 =A0 end
=A0end

=A0s =3D "abc"
=A0p third_char_as_fixnum(s) # =3D=3D> 99

This works in both 1.9.1 and 1.8.7

=A0 =A0 def third_char_as_fixnum(s)
=A0 =A0 =A0 s[2].ord
=A0 =A0 end

Because Integer#ord returns the integer receiver.
ruby -v -e 'p "foo"[2].ord'
ruby 1.8.6 (2007-09-24 patchlevel 111) [i386-linux]
-e:1: undefined method `ord' for 111:Fixnum (NoMethodError)
cat foo.rb
unless 0.respond_to?:)ord)
class Integer
def ord; self; end
end
end
ruby -v -rfoo -e 'p "foo"[2].ord'
ruby 1.8.6 (2007-09-24 patchlevel 111) [i386-linux]
111

Still meets the constraint: "without adding methods to String"
:)
 
J

Joel VanderWerf

ruby -v -e 'p "foo"[2].ord'
ruby 1.8.6 (2007-09-24 patchlevel 111) [i386-linux]
-e:1: undefined method `ord' for 111:Fixnum (NoMethodError)
cat foo.rb
unless 0.respond_to?:)ord)
class Integer
def ord; self; end
end
end
ruby -v -rfoo -e 'p "foo"[2].ord'
ruby 1.8.6 (2007-09-24 patchlevel 111) [i386-linux]
111

Still meets the constraint: "without adding methods to String"
:)

That seems like a pretty good approach, actually, and it happens to be
what the snmp gem does (lib/ber.rb):

#
# Add ord method to Fixnum for forward compatibility with Ruby 1.9
#
if "a"[0].kind_of? Fixnum
unless Fixnum.methods.include? :eek:rd
class Fixnum
def ord; self; end
end
end
end
 
J

Joel VanderWerf

Joel said:
(e-mail address removed) wrote: ...

That seems like a pretty good approach, actually, and it happens to be
what the snmp gem does (lib/ber.rb):

The reason I wanted to avoid adding anything to String was that I
couldn't think of a method name that would be pretty safe from conflict
without being too verbose or obscure (String#get_nth_char_as_int ?).

It's hard to imagine Integer#ord ever meaning anything other than this
(it does in 1.8.7 and 1.9.1, as Glenn pointed out), so it seems safe to
import it from future, as they say.

Thanks everyone! (This will help bit-struct run in 1.9.)
 
D

David A. Black

Hi --

ruby -v -e 'p "foo"[2].ord'
ruby 1.8.6 (2007-09-24 patchlevel 111) [i386-linux]
-e:1: undefined method `ord' for 111:Fixnum (NoMethodError)
cat foo.rb
unless 0.respond_to?:)ord)
class Integer
def ord; self; end
end
end
ruby -v -rfoo -e 'p "foo"[2].ord'
ruby 1.8.6 (2007-09-24 patchlevel 111) [i386-linux]
111

Still meets the constraint: "without adding methods to String"
:)

That seems like a pretty good approach, actually, and it happens to be what
the snmp gem does (lib/ber.rb):

#
# Add ord method to Fixnum for forward compatibility with Ruby 1.9
#
if "a"[0].kind_of? Fixnum
unless Fixnum.methods.include? :eek:rd
class Fixnum
def ord; self; end
end
end
end

There's always a bit of fragility, since someone else might have added
an ord that does something else... unlikely, of course, but still.

Also, I didn't suggest adding String#ord because you had said you
didn't want to add methods to String (though your next post clarifies
what you meant by that). If you want to be more future-esque you could
add it to String instead of Fixnum (though that might involve one of
those unpack-based implementations and therefore not be as fast).


David

--
David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Now available: The Well-Grounded Rubyist (http://manning.com/black2)
Training! Intro to Ruby, with Black & Kastner, September 14-17
(More info: http://rubyurl.com/vmzN)
 
H

Harry Kakueki

preferably without the RUBY_VERSION test, without adding methods to
String, and without losing much efficiency compared with 1.8's String#[].

This may not be pretty, but you do not need to add anything.
It works on 1.8.6, 1.8.7, and 1.9.0 if byte is good enough.

s[2..2].each_byte{|f| p f}


Harry
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top