I am trying to understand how to design classes which take an input, do some processing, and return a result.
There is a principle in object orientated design called "Tell, don't ask"
What this generally means is you tell an object to change itself, you don't ask an object for data that you then manipulate some where else.
So when thinking about how to manage something like this in OO design you need to keep coming back to your objects and what they themselves do. In general you don't have an object that takes input from another objects, because you make the objects themselves do the work.
So taking your example there are a number of immediate design issues that spring up. You are passing a collection of pages into an unnamed object that will then process them. It is probably better to let the pages themselves handle this.
So instead of
removeHeaderFooterText(pages)
try instead
pages.each |page|
page.removeHeaderFooterText
Nothing then outside of the page object itself has to know how the heck to remove header and footer text from the page.
You have the steps to achieve this as
getBoundaryBlocks
detectRepeatingBlocks
removeBlocks
Straight away a a noun jumps out, "Boundary Blocks". A page has boundary blocks, so there shouldn't be something outside of the Page object concerned with getting boundary blocks out of the page
class Page
def removeHeaderFooterText
page_blocks.each |block|
if block.repeating_block?
page_blocks.delete(block)
See you have an object in there of a block, which itself knows how to determine if it is a repeating block or not. If it is the page removes it. The page doesn't care how the block determines if it is a repeating block or not.
This is just a quick example. To be honest I'm not up on my document layout terminology so this might not quite match what you are trying to do.
tl;dr version
The point is that in object orientated design an "algorithm" will not be represented as a single list of procedural operations to carry out.
It will instead be a set of interactions between objects. As Adele Goldberg said about Smalltalk, one of the earliest object orientated languages, "In Smalltalk, everything happens some where else"
You will (should) never have a list of algorithmic procedural instructions to carry out an algorithm. You will instead of a number of interacting objects, each with a small unit of behaviours, that working together will produce the outcome of the algorithm. Every object is a self contained unit of behaviour and the system achieves its goals by each of these units telling other units to do something.
The issue of course with this is it requires a very different way of thinking about problems and algorithms, which is why often claims of object orientated design fall back on procedural design.