Data abstraction is fundamental to most object-oriented languages โโโ in which classes are designed to encapsulate data and provide methods for controlling how that data changes (if at all) or helper methods to get the value of that data.
The Ruby Array class is an example of data abstraction. It provides a mechanism for managing an array of objects and provides operations that can be performed in this array, without having to worry about how it is organized inside it.
arr = [1,3,4,5,2,10] p arr.class
Procedural abstraction is to hide the details of the implementation of the procedure from the user. In the above example, you donโt need to know which sort method sort used internally, you just use it, assuming that the good people in the Ruby Core team have chosen the best option for you.
At the same time, Ruby may not know how to always compare the two elements present in Array . For example, the code below will not work, since Ruby does not know how to compare strings and numbers.
[1,3,4,5,"a","c","b", 2,10].sort #=> `sort': comparison of Fixnum with String failed (ArgumentError)
This allows us to connect to the implementation and help in comparison, although the basic sorting algorithm remains the same (as it abstracts from the user)
[1,3,4,5,"a","c","b", 2,10].sort { |i,j| if i.class == String and j.class == String i <=> j elsif i.class == Fixnum and j.class == Fixnum i <=> j else 0 end }
When writing code for your own problems, procedural abstraction can be used to ensure that a procedure often violates its problem in subtasks and solves each problem using a separate procedure. This allows some aspects to be expanded later (as in the above case, the comparison can be extended - thanks to Ruby blocks it was much easier). The template method template is a good technique to achieve this.