Range#member? Oddity

  • Thread starter James Edward Gray II
  • Start date
D

David Vallner

i think it's best if ruby
will let us run quickly with knives.

regards.

-a


Oh, I agree with that myself. I'm just objecting to the people that =20
complain when they trip ;P

David Vallner
 
A

Adam Shelly

------=_Part_3318_12230970.1137389593030
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

I was messing around with this range behavior after the last discussion, an=
d
I came up some code that made ranges act, at least to me:
I made range.member?(x0 =3D=3D range.to_a.member?(x) and range.spans?(x) =
=3D=3D
(range.first < x < range.last) .
I had to implement string.follows? s which works like the spaceship
operator but uses the string succession rules:

class Range
def member?(x)
f=3Dfirst.follows?(x) and f<0 && l=3Dlast.follows?(x) and l>0
end
def spans?(x)
(first<=3D>x) <=3D0 && (last<=3D>x) >=3D0
end
end

class Object
def follows? other
self<=3D>other if self.respond_to? :succ
end
end

class String
def is_numeric?
/^-?\d+$/.match(self) ? true : false
end

def case
return :upcase if self=3D=3Dself.upcase
return :downcase if self=3D=3Dself.downcase
return :mixcase
end

def follows? str
return 0 if str =3D=3D self
return 1 if self.is_after? str
return -1 if str.is_after? self
return nil
end

def is_after? str #not pretty, but it seems to work...
#split into groups of letters and digits
firstparts =3D str.split(/\W/).map{|c|c.split(/(\d+)/)}.flatten
lastparts =3D self.split(/\W/).map{|c|c.split(/(\d+)/)}.flatten
matching =3D nil
return false if lastparts.size !=3D firstparts.size
if firstparts =3D=3D [] && lastparts =3D=3D [] #both strings are all pu=
nctuation
firstparts =3D [str]; lastparts =3D [self]
end
#return false on first non-matching or non-following group
firstparts.each_index do |i|
next if firstparts =3D=3D lastparts
firstparts.split_by_case.zip(lastparts.split_by_case).each {
|f,l|
return false if f=3D=3Dnil || l=3D=3Dnil
next if (matching && l.format_match(f))
if (f.is_numeric?)
return false unless l.is_numeric? and l.to_i > f.to_i
else
return false if l.case !=3D f.case || l.cmp(f) =3D=3D -1
end
matching =3D true #this group is in the right order - the rest just
have to match by format
}
end #each
true
end

def split_by_case
letters =3D split("").zip(downcase.split(""))
same =3D (letters[0][0]!=3Dletters[0][1])
letters.inject([]){|a,l|
if (same =3D=3D (l[0]=3D=3Dl[1]))
a[-1]+=3Dl[0]
else
a<<l[0]
end
same =3D (l[0]=3D=3Dl[1])
a
}
end
def cmp str
n =3D self.length<=3D>str.length
return self<=3D>str if n=3D=3D0
n
end
def format_match str
is_numeric? =3D=3D str.is_numeric? && length =3D=3D str.length
end
end

require 'test/unit'
class TestRange < Test::Unit::TestCase
def test_memberspan
assert_equal(true, ('a'..'bb').member?('z') )
assert_equal(false, ('a'..'bb').spans?('z'))
assert_equal(false,('a'..'bb').member?('aardvark'))
assert_equal(true,('a'..'bb').spans?('aardvark'))
assert_equal(true,('a'..'bb').spans?('a'))
assert_equal(true,('a'..'bb').spans?('bb'))
assert_equal(false,(1..100).member?(101))
assert_equal(false,(1..100).spans?(101))
assert_equal(true,(1..100).member?(11))
assert_equal(true,(1..100).spans?(11))
assert_equal(true,(1.5..100).spans?(11))
assert_equal(nil,(1.5..100).member?(11))
end
end

-Adam

------=_Part_3318_12230970.1137389593030--
 

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

No members online now.

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,121
Latest member
LowellMcGu
Top