0
def bubble_sort_by(array)
  sorted = false

  until sorted
    swapped = false

    (array.length - 1).times do |i|
      if yield(array[i],array[i+1]) > 0
        array[i], array[i+1] = array[i+1], array[i]
        swapped = true
      end
    end

    if swapped == false
      sorted = true
    end
  end
  array
end


print bubble_sort_by(["hi","hello","hey"]) do |left,right|
    left.length - right.length
end

Hi I am building a method which sorts an array but accept a block. The block should take two arguments which represent the two elements currently being compared and sorting the element from the smallest to biggest.(https://www.theodinproject.com/courses/ruby-programming/lessons/advanced-building-blocks).

I am expecting the output to print ["hi", "hey", "hello"] However it results in an error message:

source_file.rb:8:in `block in bubble_sort_by': no block given (yield) (LocalJumpError)
    from source_file.rb:7:in `times'
    from source_file.rb:7:in `bubble_sort_by'
    from source_file.rb:22:in `<main>'

Can someone explain where does the error come from, and how can I fix it? Also I realised that if I change the code array (from second last line of the method block) to print array; the code prints out ["hi", "hey", "hello"] which is what I wanted and hence it should mean that my code is correct. Therefore my confusion of where did the error come from and how can i fix it?

roppo
  • 57
  • 7

1 Answers1

2

Can someone explain where does the error come from

Lack of parentheses in your code. Your block binds to print, not bubble_sort_by.

and how can I fix it?

One way is to not print on the same line, but use a temp variable

sorted = bubble_sort_by(["hi","hello","hey"]) do |left,right|
  left.length - right.length
end

print sorted

Another way is to use a curly-brace block syntax, it binds more strongly.

print bubble_sort_by(["hi","hello","hey"]) { |left,right| left.length - right.length }

The least preferred way (to me) is to parenthesize the sorting method, so that there's no doubt to which method the block belongs:

print(bubble_sort_by(["hi","hello","hey"]) do |left,right|
  left.length - right.length
end)
Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
  • This might be irrelevant, but how do you tell what is the block binded to? Also are there any docs out there on parenthesis? – roppo Aug 24 '17 at 15:22
  • 1
    @roppo With multiple chained method calls, the `do ... end` block syntax passes the block to the left-most method. With the `{ ... }` syntax, it is passed to the right-most method. See [the authoritative documentation](https://docs.ruby-lang.org/en/2.4.0/syntax/calling_methods_rdoc.html#label-Block+Argument) on the syntax for details. – Holger Just Aug 24 '17 at 15:32
  • 1
    @HolgerJust: I wouldn't call this "chaining", though. More like... "nesting"? – Sergio Tulentsev Aug 24 '17 at 15:40
  • Yeah, you are right, "nesting" would be the more correct term here. – Holger Just Aug 24 '17 at 16:25
  • 1
    @roppo: The syntax for block arguments in method calls is documented in [the paragraph titled "Block Argument" in the "Calling Methods" document in the "Syntax" section of the documentation](http://ruby-doc.org/core/doc/syntax/calling_methods_rdoc.html#label-Block+Argument). It is also documented in the [*Programming Ruby* book](https://pragprog.com/book/ruby4/programming-ruby-1-9-2-0) and maybe also the [*ISO Ruby Programming Language Specification*](http://iso.org/standard/59579.html). Also, your question has been asked and answered a couple dozen times already on [so]. – Jörg W Mittag Aug 25 '17 at 08:39