delphidabbler / codesnip

A code bank designed with Pascal in mind
https://delphidabbler.com/software/codesnip
Other
111 stars 34 forks source link

Make `TCSSSelector.AddProperty` fluent #73

Closed delphidabbler closed 1 year ago

delphidabbler commented 1 year ago

https://github.com/delphidabbler/codesnip/blob/93bc8df5c994a27d594e31176c85700ec0ee0f78/Src/UCSSBuilder.pas#L109

Convert TCSSSelector.AddProperty to be fluent and to return its Self instance to enable chained method calls.

Presently, this method is usually called in with statements. That's a code smell that would best be refactoring out. Making this proposed change would make the proposed refactoring easier.

For example, refactoring

with CSSBuilder.AddSelector('a.command-link') do
begin
  AddProperty(TCSS.ColorProp(clCommandLink));
  AddProperty(TCSS.FontStyleProp(cfsItalic));
  AddProperty(TCSS.TextDecorationProp([ctdNone]));
end;

Without the proposed change would result in something like:

var
  Sel: TCSSSelector;
begin
  Sel := CSSBuilder.AddSelector('a.command-link');
  Sel.AddProperty(TCSS.ColorProp(clCommandLink));
  Sel.AddProperty(TCSS.FontStyleProp(cfsItalic));
  Sel.AddProperty(TCSS.TextDecorationProp([ctdNone]));
end;

While with the fluent version we could write

begin
  CSSBuilder.AddSelector('a.command-link')
    .AddProperty(TCSS.ColorProp(clCommandLink))
    .AddProperty(TCSS.FontStyleProp(cfsItalic))
    .AddProperty(TCSS.TextDecorationProp([ctdNone]));
end;

Which doesn't require a local variable and is more readable.

delphidabbler commented 1 year ago

Here's a possible implementation:

function TCSSSelector.AddProperty(const CSSProp: string): TCSSSelector;
begin
  fProperties.Add(CSSProp);
  Result := Self;
end;

This changes the signature of TCSSSelector.AddProperty from a procedure to a function returning TCSSSelector.

delphidabbler commented 1 year ago

As well as changing TCSSSelector.AddProperty to be fluid a new AddPropertyIf method was added to choose between two possible properties on the fly. This means that simple conditional choices of properties don't need to break the chain of method calls.

Also refactored code using with..do statements to set CSS selectors to use new fluid methods.