# Find a best version (of a package)

**URL:** <https://rubytalk.org/t/find-a-best-version-of-a-package/11169>\
**Category:** ruby-talk\
**Created:** [23 April 2004 12:17 UTC](https://rubytalk.org/t/find-a-best-version-of-a-package/11169 "2004-04-23T12:17:14Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![saiph](https://avatars.discourse-cdn.com/v4/letter/s/ee7513/32.png) [@saiph](https://rubytalk.org/u/saiph)\
**Post date:** [23 April 2004 12:17 UTC](https://rubytalk.org/t/find-a-best-version-of-a-package/11169/1 "2004-04-23T12:17:14Z")

</div>

hi list,

i’m following the “learning ruby” path, i’ve found this list very usefull the  
last time (tnx), so i thought to send this simple example to better  
understand what’d to be a good programming style.

> **···**
>
> > expand -t 2 best\_vv
> 
> * * *
> 
> class String  
> def newer?(s)  
> b = self.dup
> 
> b.sub!(/(\w±)/, ‘’)  
> t = $+  
> s.sub!(/(\w±)/, ‘’)
> 
> return -1 if t != $+ # not the same package
> 
> while (b.sub!(/(\d+.|\d+)/, ‘’)) do  
> t = $+.chomp(‘.’)  
> s.sub!(/(\d+.|\d+)/, ‘’)
> 
> ```
> return 1 if $+ == nil
> return 1 if t.to_i > $+.chomp('.').to_i
> 
> ```
> 
> end
> 
> return 0  
> end  
> end
> 
> class Array  
> def best\_version?  
> s = 0
> 
> for i in 1..self.length() - 1 do  
> t = self[i].newer? self[s]  
> if t == 1  
> s = i  
> elsif t == -1  
> return nil  
> end  
> end
> 
> return s  
> end  
> end
> 
> ## vv = [‘ruby-2.2.5’, ‘ruby-3.2.6’, ‘ruby-5’] i = vv.best\_version? puts vv[i]
> 
> how would you write or change this?
> 
> tnx again for your time 🙂
> 
> best regards,  
> saiph
> 
> –
> 
> > here are more things in heaven and earth,  
> > horatio, than are dreamt of in your philosophy.

---

<div class="post-metadata">

**Author:** ![Laurent\_Julliard4](https://avatars.discourse-cdn.com/v4/letter/l/ebca7d/32.png) [@Laurent\_Julliard4](https://rubytalk.org/u/Laurent_Julliard4)\
**Post date:** [23 April 2004 13:24 UTC](https://rubytalk.org/t/find-a-best-version-of-a-package/11169/2 "2004-04-23T13:24:03Z")

</div>

> 

> * * *
> 
> how would you write or change this?

if you’re confident that number will be one digit all the time you  
could just write:

> > vv = [‘ruby-2.2.5’, ‘ruby-3.2.6’, ‘ruby-5’]  
> > =\> [“ruby-2.2.5”, “ruby-3.2.6”, “ruby-5”]  
> > vv.max  
> > =\> “ruby-5”

> **···**
>
> il Fri, 23 Apr 2004 21:17:14 +0900, saiph [excapersgarden@libero.it](mailto:excapersgarden@libero.it) ha scritto::

---

<div class="post-metadata">

**Author:** ![ts1](https://avatars.discourse-cdn.com/v4/letter/t/a8b319/32.png) [@ts1](https://rubytalk.org/u/ts1)\
**Post date:** [23 April 2004 13:54 UTC](https://rubytalk.org/t/find-a-best-version-of-a-package/11169/3 "2004-04-23T13:54:19Z")

</div>

> vv = ['ruby-2.2.5', 'ruby-3.2.6', 'ruby-5']  
> i = vv.best\_version?

> how would you write or change this?

Well, like said previously it's faster to do it if all your numbers have  
only one digit.

> def newer?(s)  
> def best\_version?

generally a method with ? at the end, return true or false perhaps best to  
change the name.

Something like this (not tested)

svg% cat b.rb  
#!/usr/bin/ruby  
class String  
&nbsp;&nbsp;&nbsp;REG = /\A\w+-(?=[\d.]+\z)/

&nbsp;&nbsp;&nbsp;def newer(s)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return nil unless self[REG] == s[REG]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a = self.scan(/(\d+)\.?/).flatten  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b = s.scan(/(\d+)\.?/).flatten  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.zip(b) do |x, y|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t = x.to\_i \<=\> y.to\_i  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return t unless t.zero?  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0  
&nbsp;&nbsp;&nbsp;end  
end

class Array  
&nbsp;&nbsp;&nbsp;def best\_version  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inject do |res, elem|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t = res.newer(elem)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return nil if t.nil?  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\>=0 ? res : elem  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;end  
end  
vv = ['ruby-2.2.5', 'ruby-3.2.6', 'ruby-5']  
puts vv.best\_version  
svg%

svg% b.rb  
ruby-5  
svg%

Guy Decoux

---

<div class="post-metadata">

**Author:** ![Kristof\_Bastiaensen1](https://avatars.discourse-cdn.com/v4/letter/k/9fc29f/32.png) [@Kristof\_Bastiaensen1](https://rubytalk.org/u/Kristof_Bastiaensen1)\
**Post date:** [23 April 2004 14:24 UTC](https://rubytalk.org/t/find-a-best-version-of-a-package/11169/4 "2004-04-23T14:24:13Z")

</div>

My try:

r = /ruby-([\d.]+)/  
[‘ruby-2.2.5’, ‘ruby-3.2.6’, ‘ruby-5’].max { |a, b|  
r.match(a)[1].split(“.”) \<=\> r.match(b)[1].split(“.”) }

or shorter:

[‘ruby-2.2.5’, ‘ruby-3.2.6’, ‘ruby-5’].sort\_by { |s|  
/ruby-([\d.]+)/.match(s)[1].split(“.”) }[-1]

(I am not sure which one performs the best).

My opinion about programming style is: make things as  
simple as you can. Don’t create extra helper classes  
etc if you don’t need them.

Kristof

> **···**
>
> On Fri, 23 Apr 2004 21:17:14 +0900, saiph wrote:
> 
> > hi list,
> > 
> > i’m following the “learning ruby” path, i’ve found this list very usefull the  
> > last time (tnx), so i thought to send this simple example to better  
> > understand what’d to be a good programming style.
> > 
> > > expand -t 2 best\_vv
> > 
> > * * *
> > 
> > class String  
> > def newer?(s)  
> > b = self.dup
> > 
> > b.sub!(/(\w±)/, ‘’)  
> > t = $+  
> > s.sub!(/(\w±)/, ‘’)
> > 
> > return -1 if t != $+ # not the same package
> > 
> > while (b.sub!(/(\d+.|\d+)/, ‘’)) do  
> > t = $+.chomp(‘.’)  
> > s.sub!(/(\d+.|\d+)/, ‘’)
> > 
> > ```
> > return 1 if $+ == nil
> > return 1 if t.to_i > $+.chomp('.').to_i
> > 
> > ```
> > 
> > end
> > 
> > return 0  
> > end  
> > end
> > 
> > class Array  
> > def best\_version?  
> > s = 0
> > 
> > for i in 1…self.length() - 1 do  
> > t = self[i].newer? self[s]  
> > if t == 1  
> > s = i  
> > elsif t == -1  
> > return nil  
> > end  
> > end
> > 
> > return s  
> > end  
> > end
> > 
> > ## vv = [‘ruby-2.2.5’, ‘ruby-3.2.6’, ‘ruby-5’] i = vv.best\_version? puts vv[i]
> > 
> > how would you write or change this?
> > 
> > tnx again for your time 🙂
> > 
> > best regards,  
> > saiph

---

<div class="post-metadata">

**Author:** ![Mark\_Hubbart](https://avatars.discourse-cdn.com/v4/letter/m/b77776/32.png) [@Mark\_Hubbart](https://rubytalk.org/u/Mark_Hubbart)\
**Post date:** [23 April 2004 17:37 UTC](https://rubytalk.org/t/find-a-best-version-of-a-package/11169/5 "2004-04-23T17:37:57Z")

</div>

first, I would suggest more comments in the code 🙂 at least something  
above the method telling what it does. That makes it so others can see  
at a glance what it is for, and rdoc can document it properly.

query methods (foo?()) generally return true/false. Also, I suspect  
that comparing different packages should raise an error, not return -1.

Otherwise, I think maybe it could be condensed down a bit…

class String  
# compares package version strings  
def newer?(other)  
this, that = split(/-/), other.split(/-/)

```
   # check that package names match
   if this[0] != that[0]
   	raise ArgumentError, "package names do not match"
   end

   # compare each section
   this[1].split(".").zip( that[1].split(".") ) do |a,b|
     a, b = a.to_i, b.to_i
     return a > b if a != b
   end

   # neither one was larger:
   return false
 end

```

end

class Array  
# returns the highest version string in an array  
def best\_version  
inject{|a,b| a.newer?(b) ? b : a }  
end  
end

cheers,  
–Mark

> **···**
>
> On Apr 23, 2004, at 5:17 AM, saiph wrote:
> 
> > hi list,
> > 
> > i’m following the “learning ruby” path, i’ve found this list very  
> > usefull the  
> > last time (tnx), so i thought to send this simple example to better  
> > understand what’d to be a good programming style.
> > 
> > > expand -t 2 best\_vv
> > 
> > * * *
> > 
> > class String  
> > def newer?(s)  
> > b = self.dup
> > 
> > b.sub!(/(\w±)/, ‘’)  
> > t = $+  
> > s.sub!(/(\w±)/, ‘’)
> > 
> > return -1 if t != $+ # not the same package
> > 
> > while (b.sub!(/(\d+.|\d+)/, ‘’)) do  
> > t = $+.chomp(‘.’)  
> > s.sub!(/(\d+.|\d+)/, ‘’)
> > 
> > ```
> > return 1 if $+ == nil
> > return 1 if t.to_i > $+.chomp('.').to_i
> > 
> > ```
> > 
> > end
> > 
> > return 0  
> > end  
> > end
> > 
> > class Array  
> > def best\_version?  
> > s = 0
> > 
> > for i in 1…self.length() - 1 do  
> > t = self[i].newer? self[s]  
> > if t == 1  
> > s = i  
> > elsif t == -1  
> > return nil  
> > end  
> > end
> > 
> > return s  
> > end  
> > end
> > 
> > ## vv = [‘ruby-2.2.5’, ‘ruby-3.2.6’, ‘ruby-5’] i = vv.best\_version? puts vv[i]
> > 
> > how would you write or change this?

---

<div class="post-metadata">

**Author:** ![Ara.T.Howard](https://avatars.discourse-cdn.com/v4/letter/a/a8b319/32.png) [@Ara.T.Howard](https://rubytalk.org/u/Ara.T.Howard)\
**Post date:** [23 April 2004 15:14 UTC](https://rubytalk.org/t/find-a-best-version-of-a-package/11169/6 "2004-04-23T15:14:11Z")

</div>

i think the problem with both these approaches are that they may not reflect  
the semantics of version numbers! for instance, i use the linux/libtool style  
of versioning (the same used by ld.so - man ld.so)

see

[http://raa.ruby-lang.org/list.rhtml?name=library](http://raa.ruby-lang.org/list.rhtml?name=library)

specifically

[RDoc Documentation](http://www.codeforpeople.com//lib/ruby/library/library-0.0.0/doc/)

so

if my code requires version 2.1.5, i could use 7.5.0 but NOT 3.0.4

-a

> **···**
>
> On Fri, 23 Apr 2004, Kristof Bastiaensen wrote:
> 
> > On Fri, 23 Apr 2004 21:17:14 +0900, saiph wrote:
> > 
> > > hi list,
> > > 
> > > i’m following the “learning ruby” path, i’ve found this list very usefull the  
> > > last time (tnx), so i thought to send this simple example to better  
> > > understand what’d to be a good programming style.
> > > 
> > > > expand -t 2 best\_vv
> > > 
> > > * * *
> > > 
> > > class String  
> > > def newer?(s)  
> > > b = self.dup
> > > 
> > > b.sub!(/(\w±)/, ‘’)  
> > > t = $+  
> > > s.sub!(/(\w±)/, ‘’)
> > > 
> > > return -1 if t != $+ # not the same package
> > > 
> > > while (b.sub!(/(\d+.|\d+)/, ‘’)) do  
> > > t = $+.chomp(‘.’)  
> > > s.sub!(/(\d+.|\d+)/, ‘’)
> > > 
> > > ```
> > > return 1 if $+ == nil
> > > return 1 if t.to_i > $+.chomp('.').to_i
> > > 
> > > ```
> > > 
> > > end
> > > 
> > > return 0  
> > > end  
> > > end
> > > 
> > > class Array  
> > > def best\_version?  
> > > s = 0
> > > 
> > > for i in 1..self.length() - 1 do  
> > > t = self[i].newer? self[s]  
> > > if t == 1  
> > > s = i  
> > > elsif t == -1  
> > > return nil  
> > > end  
> > > end
> > > 
> > > return s  
> > > end  
> > > end
> > > 
> > > ## vv = [‘ruby-2.2.5’, ‘ruby-3.2.6’, ‘ruby-5’] i = vv.best\_version? puts vv[i]
> > > 
> > > how would you write or change this?
> > > 
> > > tnx again for your time 🙂
> > > 
> > > best regards,  
> > > saiph
> > 
> > My try:
> > 
> > r = /ruby-([\d.]+)/  
> > [‘ruby-2.2.5’, ‘ruby-3.2.6’, ‘ruby-5’].max { |a, b|  
> > r.match(a)[1].split(“.”) \<=\> r.match(b)[1].split(“.”) }
> > 
> > or shorter:
> > 
> > [‘ruby-2.2.5’, ‘ruby-3.2.6’, ‘ruby-5’].sort\_by { |s|  
> > /ruby-([\d.]+)/.match(s)[1].split(“.”) }[-1]
> > 
> > (I am not sure which one performs the best).
> > 
> > My opinion about programming style is: make things as  
> > simple as you can. Don’t create extra helper classes  
> > etc if you don’t need them.
> > 
> > Kristof
> 
> # –
> 
> > EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov  
> > PHONE :: 303.497.6469  
> > ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328  
> > URL :: [Solar-Terrestrial Physics Data | NCEI](http://www.ngdc.noaa.gov/stp/)  
> > TRY :: for l in ruby perl;do $l -e “print "\x3a\x2d\x29\x0a"”;done  
> > ===============================================================================

---

<div class="post-metadata">

**Author:** ![saiph](https://avatars.discourse-cdn.com/v4/letter/s/ee7513/32.png) [@saiph](https://rubytalk.org/u/saiph)\
**Post date:** [24 April 2004 19:01 UTC](https://rubytalk.org/t/find-a-best-version-of-a-package/11169/7 "2004-04-24T19:01:10Z")

</div>

i found very good your advices!

← snip →   
inject{|a,b| a.newer?(b) ? b : a }  
 ← snip →

it s, i think, inject{|a,b| a.newer?(b) ? a : b }

tnx again.

> **···**
>
> –
> 
> > here are more things in heaven and earth,  
> > horatio, than are dreamt of in your philosophy.

---

<div class="post-metadata">

**Author:** ![Joel\_VanderWerf1](https://avatars.discourse-cdn.com/v4/letter/j/94ad74/32.png) [@Joel\_VanderWerf1](https://rubytalk.org/u/Joel_VanderWerf1)\
**Post date:** [23 April 2004 20:17 UTC](https://rubytalk.org/t/find-a-best-version-of-a-package/11169/8 "2004-04-23T20:17:49Z")

</div>

Ara.T.Howard wrote:

> i think the problem with both these approaches are that they may not reflect  
> the semantics of version numbers! for instance, i use the linux/libtool style  
> of versioning (the same used by ld.so - man ld.so)
> 
> see
> 
> [http://raa.ruby-lang.org/list.rhtml?name=library](http://raa.ruby-lang.org/list.rhtml?name=library)
> 
> specifically
> 
> [http://www.codeforpeople.com//lib/ruby/library/library-0.0.0/doc/](http://www.codeforpeople.com//lib/ruby/library/library-0.0.0/doc/)
> 
> so
> 
> if my code requires version 2.1.5, i could use 7.5.0 but NOT 3.0.4

That was an interesting read on version number semantics, but your  
example conflicts with my understanding. Wouldn’t the 2.1.5 requirement  
be satisfied by 3.0.1 and in fact by 3.0.x for x\>=1? The last digit,  
IIRC, is a measure of backwards compatibility with previous interface  
versions. So 3.0.4 isn’t even possible, because there are at most 3  
previous interface versions, not 4. By the same token 7.5.0 doesn’t work  
with 2.x.y thru 6.x.y because it’s “interface age” is only 0.

Did I misunderstand?

---

<div class="post-metadata">

**Author:** ![Mark\_Hubbart](https://avatars.discourse-cdn.com/v4/letter/m/b77776/32.png) [@Mark\_Hubbart](https://rubytalk.org/u/Mark_Hubbart)\
**Post date:** [24 April 2004 20:11 UTC](https://rubytalk.org/t/find-a-best-version-of-a-package/11169/9 "2004-04-24T20:11:13Z")

</div>

> i found very good your advices!
> 
> ← snip →   
> inject{|a,b| a.newer?(b) ? b : a }  
> ← snip →
> 
> it s, i think, inject{|a,b| a.newer?(b) ? a : b }

Ahh, yes 🙂 #newer? is a bit ambiguous, and I got mixed up as to  
whether (a.newer? b == true) meant that a was newer or b was 🙂

Actually, I’d prefer a compare here, a modified version of \<=\> that  
takes numbers into account. That would remove nay ambiguity.

cheers,  
–Mark

> **···**
>
> On Apr 24, 2004, at 12:01 PM, saiph wrote:
> 
> > tnx again.
> > 
> > –
> > 
> > > here are more things in heaven and earth,  
> > > horatio, than are dreamt of in your philosophy.

---

<div class="post-metadata">

**Author:** ![Ara.T.Howard](https://avatars.discourse-cdn.com/v4/letter/a/a8b319/32.png) [@Ara.T.Howard](https://rubytalk.org/u/Ara.T.Howard)\
**Post date:** [23 April 2004 20:44 UTC](https://rubytalk.org/t/find-a-best-version-of-a-package/11169/10 "2004-04-23T20:44:07Z")

</div>

no. you are correct - i swapped revision with age in my example. sorry for  
the confusion.

i’d really like to see something like this in the core. i use it here at work  
were we have (in house joke) single test/production environment and it allows  
me to upgrade libs while our near-realtime system is running because in  
anything important i require an **exact** version. only in developemnt or  
less critical code to i allow a ‘compatible’ version to be found… it’s a  
real comfort to be able to upgrade libs without breaking existing code.

the method i use is:

lib/package-0.0.0.rb  
lib/package.rb

where package.rb is a link to package-0.0.0.rb. the install will obviously  
install both and i end up with

package-0.0.0.rb  
package-0.1.0.rb  
package-0.2.0.rb  
package-1.0.0.rb  
package-1.0.1.rb  
package-2.0.0.rb  
package.rb

in site\_ruby. i try to keep stuff up to date - but i don’t HAVE to.

-a

> **···**
>
> On Sat, 24 Apr 2004, Joel VanderWerf wrote:
> 
> > Ara.T.Howard wrote:
> > 
> > > i think the problem with both these approaches are that they may not reflect  
> > > the semantics of version numbers! for instance, i use the linux/libtool style  
> > > of versioning (the same used by ld.so - man ld.so)
> > > 
> > > see
> > > 
> > > [http://raa.ruby-lang.org/list.rhtml?name=library](http://raa.ruby-lang.org/list.rhtml?name=library)
> > > 
> > > specifically
> > > 
> > > [RDoc Documentation](http://www.codeforpeople.com//lib/ruby/library/library-0.0.0/doc/)
> > > 
> > > so
> > > 
> > > if my code requires version 2.1.5, i could use 7.5.0 but NOT 3.0.4
> > 
> > That was an interesting read on version number semantics, but your  
> > example conflicts with my understanding. Wouldn’t the 2.1.5 requirement  
> > be satisfied by 3.0.1 and in fact by 3.0.x for x\>=1? The last digit,  
> > IIRC, is a measure of backwards compatibility with previous interface  
> > versions. So 3.0.4 isn’t even possible, because there are at most 3  
> > previous interface versions, not 4. By the same token 7.5.0 doesn’t work  
> > with 2.x.y thru 6.x.y because it’s “interface age” is only 0.
> > 
> > Did I misunderstand?
> 
> # –
> 
> > EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov  
> > PHONE :: 303.497.6469  
> > ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328  
> > URL :: [Solar-Terrestrial Physics Data | NCEI](http://www.ngdc.noaa.gov/stp/)  
> > TRY :: for l in ruby perl;do $l -e “print "\x3a\x2d\x29\x0a"”;done  
> > ===============================================================================
