2

Is there an easy and fast operation to just strip the last path of a directory of a path in ruby without using regex?

path examples:

has="/my/to/somewhere/id"
wants="/my/to/somewhere"

Currently I am using:

path.split('/')[0...-1].join('/')

For has I will always know the id so I could also use:

path.sub("/#{id}", '')

So my question is really, which operation is faster??

mahatmanich
  • 10,791
  • 5
  • 63
  • 82
  • 1
    the array index "-1" is the last element, so you'll get the whole array with [0..-1]. Try `path.split('/')[0..-2].join('/')` Note also it's two dots, not 3, ie `[0..-2]` not `[0...-2]` – Max Williams Mar 10 '15 at 12:55
  • You can also try `path.delete(path.split("/").last)` – Sonalkumar sute Mar 10 '15 at 12:58
  • @MaxWilliams what is the difference? 2 and 3 dots? – mahatmanich Mar 10 '15 at 13:15
  • 1
    @mahatmanich i thought that the three dot version was just a mistake but turns out it's real and you were using it correctly. "two dots" returns the last element as well, "three dots" doesn't return the last element. eg `(0..3).to_a => [0, 1, 2, 3]`, `(0...3).to_a => [0, 1, 2]`, `["a", "b", "c", "d"][0..-1] => ["a", "b", "c", "d"]`, `["a", "b", "c", "d"][0...-1] => ["a", "b", "c"]`. See http://stackoverflow.com/questions/9690801/difference-between-double-dot-and-triple-dot-in-range-generation. Thanks for helping me discover this. – Max Williams Mar 10 '15 at 13:36
  • @MaxWilliams yeah I wanted to exclude the last el :-) glad we could learn something from each other :-) just found the two dotted :-) and didn't know :D – mahatmanich Mar 10 '15 at 14:01
  • The two dotted is much more commonly used, and if you are working with other programmers then the three-dot version could be a bit of a trap for them. I think a lot of people don't know about the three-dot, it's not very well documented. – Max Williams Mar 10 '15 at 14:14

3 Answers3

4

Well, you can use Pathname#parent method.

require 'pathname'

Pathname.new("/my/to/somewhere/id").parent
# => #<Pathname:/my/to/somewhere>
Pathname.new("/my/to/somewhere/id").parent.to_s
# => "/my/to/somewhere"
Arup Rakshit
  • 116,827
  • 30
  • 260
  • 317
3

Using Pathname is a little bit faster than split. On my machine, running a million times:

require 'benchmark'
require 'pathname'

n = 1000000
id = "id"
Benchmark.bm do |x|
  x.report("pathname: ") { n.times { Pathname("/my/to/somewhere/id").dirname.to_s } }
  x.report("split:") { n.times { "/my/to/somewhere/id".split('/')[0...-1].join('/') } }
  x.report("path.sub:") { n.times { "/my/to/somewhere/id".sub("/#{id}", '') } }
end

I have got the following results:

              user     system      total        real
pathname:   1.550000   0.000000   1.550000 (  1.549925)
split:      1.810000   0.000000   1.810000 (  1.806914)
path.sub:   1.030000   0.000000   1.030000 (  1.030306)
victorkt
  • 13,992
  • 9
  • 52
  • 51
3

There is a method for Pathname - split, which:

Returns the dirname and the basename in an Array.

require 'pathname'

Pathname.new("/my/to/somewhere/id").split.first.to_s
# => "/my/to/somewhere"

Hope that helps!

Paweł Dawczak
  • 9,519
  • 2
  • 24
  • 37