String/Range comparison problem - ruby

This make sense for things like :
irb(main):001:0> ["b", "aa", "d", "dd"].sort
=> ["aa", "b", "d", "dd"]
But doesn't for :
irb(main):002:0> ("B".."AA").each{ |x| print "#{x}," }
=> "B".."AA"
should produce :
B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,=> "B".."AA" but "B" > "AA" => true
Unlike "B".."BA" ("B" > "BA" => false) :
irb(main):003:0> ("B".."BA").each{ |x| print "#{x}," }
B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AS,AT,AU,AV,AW,AX,AY,AZ,BA,=> "B".."BA"
Any advice to make "b".."aa" work as expected in ruby ?
I use
irb 0.9.5(05/04/13) ruby 1.8.7
(2009-06-12 patchlevel 174) [i486-linux]
Linux 2.6.31-19-generic #56-Ubuntu SMP Thu Jan 28 01:26:53 UTC 2010 i686 GNU/Linux

The best way to do this is to subclass String and redefine the comparison operator to meet your needs. Then use your new class to make the range.
class MyString < String
def initialize str=""
super str
end
def <=>(other)
length_cmp = self.length <=> other.length
return length_cmp unless length_cmp == 0
super other
end
end
Now you can ensure that a column appears before another.
"b" < "aa" #=> false
MyString.new("b") < MyString.new("aa") #=> true
N.B.: Only the string on the left side of any comparison operator needs to be of class MyString:
MyString.new("b") < "aa" #=> true
"aa" > MyString.new("b") #=> false

It looks like Ruby is using succ, but first it checks for end>=start, and since that is false here, it doesn't even try.
Admittedly String#succ is a weird beast here: a string's successor isn't always greater than the string, using its own comparison methods. So I'm not sure if this is technically a bug or not. It does look pretty confusing if you don't know this undocumented check, though.
Then again, judging by some of the other answers here, it looks like it does work as you expect in some versions of Ruby, so maybe it was fixed in 1.9?

It is true that in class String, <=> and String#succ are not completely harmonized
I suppose it would be nice if for each a, b where b eventually is produced from a.succ.succ..., it was also true that a <=> b returned -1. One reason this would be nice is that it is in fact precisely <=> and succ that are used to implement ranges in the first place. Consequently, as you have noted, a Ruby String range where .succ would eventually complete the expansion doesn't work because a <=> test contradicts it and terminates the loop.
So yes, the ordering, at least for String, that is defined by <=> doesn't match the #succ method ordering. This is one reason that some developers avoid using succ.

Any advice to make "b".."aa" work as expected in ruby ?
This DOESN'T work in ruby 1.8.7 (2009-06-12 patchlevel 174) nor in ruby 1.9.1p376 (2009-12-07 revision 26041) [i486-linux]
"b".."ba" does work...
irb(main):001:0> ("b".."ba").each {|x| print "#{x} "}
b c d e f g h i j k l m n o p q r s t u v w x y z aa ab ac ad ae af ag ah ai aj ak al am an ao ap aq ar as at au av aw ax ay az ba => "b".."ba"

This was reported as a bug in Ruby here. The results depend on which version of Ruby you are running. There is a difference between versions 1.8.6 and 1.9.1.

Related

Is order of a Ruby hash literal guaranteed?

Ruby, since v1.9, supports a deterministic order when looping through a hash; entries added first will be returned first.
Does this apply to literals, i.e. will { a: 1, b: 2 } always yield a before b?
I did a quick experiment with Ruby 2.1 (MRI) and it was in fact consistent, but to what extent is this guaranteed by the language to work on all Ruby implementations?
There are couple of locations where this could be specified, i.e. a couple of things that are considered "The Ruby Language Specification":
the ISO Ruby Language Specification
the RubySpec project
the YARV testsuite
The Ruby Programming Language book by matz and David Flanagan
The ISO spec doesn't say anything about Hash ordering: it was written in such a way that all existing Ruby implementations are automatically compliant with it, without having to change, i.e. it was written to be descriptive of current Ruby implementations, not prescriptive. At the time the spec was written, those implementations included MRI, YARV, Rubinius, JRuby, IronRuby, MagLev, MacRuby, XRuby, Ruby.NET, Cardinal, tinyrb, RubyGoLightly, SmallRuby, BlueRuby, and others. Of particular interest are MRI (which only implements 1.8) and YARV (which only implements 1.9 (at the time)), which means that the spec can only specify behavior which is common to 1.8 and 1.9, which Hash ordering is not.
The RubySpec project was abandoned by its developers out of frustration that the ruby-core developers and YARV developers never recognized it. It does, however, (implicitly) specify that Hash literals are ordered left-to-right:
new_hash(1 => 2, 4 => 8, 2 => 4).keys.should == [1, 4, 2]
That's the spec for Hash#keys, however, the other specs test that Hash#values has the same order as Hash#keys, Hash#each_value and Hash#each_key has the same order as those, and Hash#each_pair and Hash#each have the same order as well.
I couldn't find anything in the YARV testsuite that specifies that ordering is preserved. In fact, I couldn't find anything at all about ordering in that testsuite, quite the opposite: the tests go to great length to avoid depending on ordering!
The Flanagan/matz book kinda-sorta implicitly specifies Hash literal ordering in section 9.5.3.6 Hash iterators. First, it uses much the same formulation as the docs:
In Ruby 1.9, however, hash elements are iterated in their insertion order, […]
But then it goes on:
[…], and that is the order shown in the following examples:
And in those examples, it actually uses a literal:
h = { :a=>1, :b=>2, :c=>3 }
# The each() iterator iterates [key,value] pairs
h.each {|pair| print pair } # Prints "[:a, 1][:b, 2][:c, 3]"
# It also works with two block arguments
h.each do |key, value|
print "#{key}:#{value} " # Prints "a:1 b:2 c:3"
end
# Iterate over keys or values or both
h.each_key {|k| print k } # Prints "abc"
h.each_value {|v| print v } # Prints "123"
h.each_pair {|k,v| print k,v } # Prints "a1b2c3". Like each
In his comment, #mu is too short mentioned that
h = { a: 1, b: 2 } is the same as h = { }; h[:a] = 1; h[:b] = 2
and in another comment that
nothing else would make any sense
Unfortunately, that is not true:
module HashASETWithLogging
def []=(key, value)
puts "[]= was called with [#{key.inspect}] = #{value.inspect}"
super
end
end
class Hash
prepend HashASETWithLogging
end
h = { a: 1, b: 2 }
# prints nothing
h = { }; h[:a] = 1; h[:b] = 2
# []= was called with [:a] = 1
# []= was called with [:b] = 2
So, depending on how you interpret that line from the book and depending on how "specification-ish" you judge that book, yes, ordering of literals is guaranteed.
From the documentation:
Hashes enumerate their values in the order that the corresponding keys
were inserted.

Multiple Kernel#local_variables entries with block local parameters

I am using this version of Ruby on Arch Linux. I also tried the first code snippet in ruby 1.9, which had the same results.
ruby -v
ruby 2.1.0p0 (2013-12-25 revision 44422) [x86_64-linux]
uname -a
Linux ryantm0j132 3.12.7-2-ARCH #1 SMP PREEMPT Sun Jan 12 13:09:09 CET 2014 x86_64 GNU/Linux
These three snippets below are separate programs.
When I use block local variables that shadow a variable the local_variables array contains 3 entries:
a = 1
puts local_variables.inspect #=> [:a]
proc { |;a|
puts local_variables.inspect #=> [:a,:a,:a]
}.call
If I don't shadow, anything it contains 1 entry:
puts local_variables.inspect #=> []
proc { |;b|
puts local_variables.inspect #=> [:b]
}.call
Another example of the block local variable not shadowing anything:
a = 1
puts local_variables.inspect #=> [:a]
proc { |;b|
puts local_variables.inspect #=> [:b,:a]
}.call
Is there some reason for these extra entries in the first case? Is it a bug in ruby?
It looks like I finally got why there are three of them. That’s out of my competence to decide whether this is a bug.
Let’s take a look at the bindings:
b1 = binding
a = 1
puts proc { |b2=binding; a|
a = 3
"T: #{b1}, B: #{b2}, L: #{binding}\n" +
"TV: #{b1.eval('a')}, BV: #{b2.eval('a')}, LV: #{binding.eval('a')}"
}.call
# ⇒ T: #<Binding:0x0000000294ef88>,
# ⇒ B: #<Binding:0x0000000294de58>,
# ⇒ L: #<Binding:0x0000000294dd68>
# ⇒ T: 1, B: 3, L: 3
It seems there are three Binding objects, each having the local variable name added to the list if and only it was shadowed. Binding b2, though it is a separate instance, has affected by a = 3 setting.
Probably it was made to simplify the local_variables discounting.
This has been confirmed as a bug on the Ruby issue tracker page where I reported it.

How to check if the RUBY_VERSION is greater than a certain version?

Before I split the RUBY_VERSION string on a period and convert the bits into integers and so on, is there a simpler way to check from a Ruby program if the current RUBY_VERSION is greater than X.X.X?
Ruby's Gem library can do version number comparisons:
require 'rubygems' # not needed with Ruby 1.9+
ver1 = Gem::Version.new('1.8.7') # => #<Gem::Version "1.8.7">
ver2 = Gem::Version.new('1.9.2') # => #<Gem::Version "1.9.2">
ver1 <=> ver2 # => -1
See http://rubydoc.info/stdlib/rubygems/1.9.2/Gem/Version for more info.
User diedthreetimes' answer is much simpler, and the method I use... except it uses string comparison, which is not best practice for version numbers. Better to use numeric array comparison like this:
version = RUBY_VERSION.split('.').map { |x| x.to_i }
if (version <=> [1, 8, 7]) >= 1
...
end
Instead of comparing version number, then perhaps check if the method exist, like this:
text = "hello world"
find = "hello "
if String.method_defined? :delete_prefix!
# Introduced with Ruby 2.5.0, 2017-10-10, https://blog.jetbrains.com/ruby/2017/10/10-new-features-in-ruby-2-5/
text.delete_prefix!(find)
else
text.sub!(/\A#{Regexp.escape(find)}/, '')
end
p text # => "world"

Automatic counter in Ruby for each?

I want to use a for-each and a counter:
i=0
for blah in blahs
puts i.to_s + " " + blah
i+=1
end
Is there a better way to do it?
Note: I don't know if blahs is an array or a hash, but having to do blahs[i] wouldn't make it much sexier. Also I'd like to know how to write i++ in Ruby.
Technically, Matt's and Squeegy's answer came in first, but I'm giving best answer to paradoja so spread around the points a bit on SO. Also his answer had the note about versions, which is still relevant (as long as my Ubuntu 8.04 is using Ruby 1.8.6).
Should've used puts "#{i} #{blah}" which is a lot more succinct.
As people have said, you can use
each_with_index
but if you want indices with an iterator different to "each" (for example, if you want to map with an index or something like that) you can concatenate enumerators with the each_with_index method, or simply use with_index:
blahs.each_with_index.map { |blah, index| something(blah, index)}
blahs.map.with_index { |blah, index| something(blah, index) }
This is something you can do from ruby 1.8.7 and 1.9.
[:a, :b, :c].each_with_index do |item, i|
puts "index: #{i}, item: #{item}"
end
You can't do this with for. I usually like the more declarative call to each personally anyway. Partly because its easy to transition to other forms when you hits the limit of the for syntax.
Yes, it's collection.each to do loops, and then each_with_index to get the index.
You probably ought to read a Ruby book because this is fundamental Ruby and if you don't know it, you're going to be in big trouble (try: http://poignantguide.net/ruby/).
Taken from the Ruby source code:
hash = Hash.new
%w(cat dog wombat).each_with_index {|item, index|
hash[item] = index
}
hash #=> {"cat"=>0, "wombat"=>2, "dog"=>1}
If you don't have the new version of each_with_index, you can use the zip method to pair indexes with elements:
blahs = %w{one two three four five}
puts (1..blahs.length).zip(blahs).map{|pair|'%s %s' % pair}
which produces:
1 one
2 two
3 three
4 four
5 five
As to your question about doing i++, well, you cannot do that in Ruby. The i += 1 statement you had is exactly how you're supposed to do it.
If you want to get index of ruby for each, then you can use
.each_with_index
Here is an example to show how .each_with_index works:
range = ('a'..'z').to_a
length = range.length - 1
range.each_with_index do |letter, index|
print letter + " "
if index == length
puts "You are at last item"
end
end
This will print:
a b c d e f g h i j k l m n o p q r s t u v w x y z You are at last item
The enumerating enumerable series is pretty nice.
If blahs is a class that mixes in Enumerable, you should be able to do this:
blahs.each_with_index do |blah, i|
puts("#{i} #{blah}")
end

How does Ruby 1.9 handle character cases in source code?

In Ruby 1.8 and earlier,
Foo
is a constant (a Class, a Module, or another constant). Whereas
foo
is a variable. The key difference is as follows:
module Foo
bar = 7
BAZ = 8
end
Foo::BAZ
# => 8
Foo::bar
# NoMethodError: undefined method 'bar' for Foo:Module
That's all well and good, but Ruby 1.9 allows UTF-8 source code. So is ℃ "uppercase" or "lowecase" as far as this is concerned? What about ⊂ (strict subset) or Ɖfoo?
Is there a general rule?
Later:
Ruby-core is already considering some of the mathematical operators. For example
module Kernel
def √(num)
...
end
def ∑(*args)
...
end
end
would allow
x = √2
y = ∑(1, 45, ...)
I would love to see
my_proc = λ { |...| ... }
x ∈ my_enumerable # same as my_enumerable.include?(x)
my_infinite_range = (1..∞)
return 'foo' if x ≠ y
2.21 ≈ 2.2
OK, my joking answer didn't go down so well.
This mailing list question, with answer from Matz indicates that Ruby 1.9's built in String#upcase and String#downcase methods will only handle ASCII characters.
Without testing it myself, I would see this as strong evidence that all non-ascii characters in source code will likely be considered lowercase.
Can someone download and compile the latest 1.9 and see?
I don't know what ruby would do if you used extended UTF8 characters as identifiers in your source code, but I know what I would do, which would be to slap you upside the back of the head and tell you DON'T DO THAT
I would love to see
my_proc = λ { |...| ... }
x ∈ my_enumerable # same as my_enumerable.include?(x)
my_infinite_range = (1..∞)
return 'foo' if x ≠ y
2.21 ≈ 2.2
I would love to see someone trying to type that program on an English keyboard :P
In Ruby 1.9.2-p0 (YARV) the result is the same as in the original post (i.e., Foo::bar #=> # NoMethodError: undefined method 'bar' for Foo:Module). Also, letters with accent are unfortunately not considered as being upper nor lower and related methods produce no result.
Examples:
"á".upcase
=> "á"
"á" == "Á".downcase
=> false
I can't get IRB to accept UTF-8 characters, so I used a test script (/tmp/utf_test.rb).
"λ" works fine as a variable name:
# encoding: UTF-8
λ = 'foo'
puts λ
# from the command line:
> ruby -KU /tmp/utf_test.rb
foo
"λ" also works fine as a method name:
# encoding: UTF-8
Kernel.class_eval do
alias_method :λ, :lambda
end
(λ { puts 'hi' }).call
# from the command line:
> ruby -KU /tmp/utf_test.rb:
hi
It doesn't work as a constant, though:
# encoding: UTF-8
Object.const_set :λ, 'bar'
# from the command line:
> ruby -KU /tmp/utf_test.rb:
utf_test.rb:2:in `const_set': wrong constant name λ (NameError)
Nor does the capitalized version:
# encoding: UTF-8
Object.const_set :Λ, 'bar'
# from the command line:
> ruby -KU /tmp/utf_test.rb:
utf_test.rb:2:in `const_set': wrong constant name Λ (NameError)
My suspicion is that constant names must start with a capital ASCII letter (must match /^[A-Z]/).

Resources