0

I have in the html the location variable sometimes is used with a class called "result-hood" sometimes is used with another class called "nearby"

    location = result.search('span.result-hood').text[2..-2]
    location2 = result.search('span.nearby').text[2..-2]

so if one of the above classes is not used the result is nill, my question is how to get always the one that is not nill, I was thinking about the ternary operator "?" , but don't know how to use it. Thanks,

user1034127
  • 349
  • 3
  • 5
  • 14

4 Answers4

4

You want the || ("or") operator:

    location || location2

It returns the left side if that is not nil or false, and otherwise it returns the right side.

matthewd
  • 4,332
  • 15
  • 21
3

CSS supports logical or operations using a comma as the delimiter, so your selector can just be:

location = result.search('span.result-hood,span.nearby').text[2..-2]

XPath also supports logical or operator itself, the equivalent XPath would look like

location = result.search('//span[@class="result-hood"]|//span[@class="nearby"]').text[2..-2]
engineersmnky
  • 25,495
  • 2
  • 36
  • 52
Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160
  • It does not work C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/nokogiri-1.8.4-x64-mingw32/lib/nokogiri/css/parser_extras.rb:87:in `on_error': unexpected '|' after '[#, #]>]' (Nokogiri::CSS::SyntaxError) – user1034127 Aug 23 '18 at 16:54
  • I didn’t know `nokogiri` is as stupid. `result.xpath('//span[@class="result-hood"] | //span[@class="nearby"]')` then. – Aleksei Matiushkin Aug 23 '18 at 16:56
  • 2
    @mudasobwa it is not that `nokogiri` is stupid it is that you answered the question using a mutation of `css` and `xpath` syntax and nokogiri saw it as css. For `css` the pattern would be `'span.result-hood,span.nearby'` because comma is `CSS`'s logical or. Please feel free to append this to your answer as it is a better choice than the "correct" answer in this case. [Example](https://repl.it/@engineersmnky/NokogiriPathSearching) – engineersmnky Aug 23 '18 at 17:44
1

Ternary operator in ruby:

loc = location.nil? ? location2 : location

Hope this works.

Arihant
  • 735
  • 5
  • 14
  • Technically true, but if it's not possible or likely that `location` would be literal `false` then `location || location2` is better. – tadman Aug 23 '18 at 18:08
-1

Since you're looking for one or the other you can reduce this code to:

location = result.search('span.result-hood').text[2..-2]
   || result.search('span.nearby').text[2..-2]

Where that search operation could be fairly expensive, so why run it twice when you might need to run it only once. Now that you've minimized it like this you can take it a step further:

location = %w[ span.result-hood span.nearby ].map do |selector|
  result.search(selector).text[2..-2]
end.compact.first

This looks a little complicated but what it does is convert each selector into the text extracted from result.search(...).text[2..-2] and then take the first non-nil value.

That technically computes all possible bits of text before extracting, so you can make it "lazy" and evaluate each one in sequence instead, stopping at the first match:

location = %w[ span.result-hood span.nearby ].lazy.map do |selector|
  result.search(selector).text[2..-2]
end.select(&:itself).first

The nice thing about this approach is you can clean it up a little by declaring a constant in advance:

LOCATIONS = %w[ span.result-hood span.nearby ]

Then later you have more minimal code like this that will automatically accommodate any changes made to that array both in terms of precedence and addition of others:

location = LOCATIONS.lazy.map do |selector|
  result.search(selector).text[2..-2]
end.select(&:itself).first
tadman
  • 208,517
  • 23
  • 234
  • 262
  • 1
    while `lazy` is definitely extremely cool. In this case it has no impact if "span.result-hood" is `nil` as this will still have to be evaluated in `select`. Additionally `select(&:itself).first` is equivalent to `detect(&:itself)` – engineersmnky Aug 23 '18 at 20:25
  • `detect(&:itself)` is a distinct improvement, yeah. – tadman Aug 23 '18 at 20:31