procore-oss / blueprinter

Simple, Fast, and Declarative Serialization Library for Ruby
MIT License
1.08k stars 109 forks source link

[Feature Request] Ability to add an extension to a single Blueprint #417

Open jhollinger opened 1 month ago

jhollinger commented 1 month ago

Is there an existing issue for this?

Is your feature request related to a problem? Please describe

Extensions are only global. We have some people wanting to do something with a pre_render extension hook, but only in certain Blueprints. While that's technically achievable by adding the extension globally and doing a check on the passed-in Blueprint, that's pretty ugly.

Describe the feature you'd like to see implemented

An extension or extensions keyword in Blueprinter classes and views. I think they should be purely additive and inheritable across views. This is similar to how transformers can be used.

Describe alternatives you've considered

transform looks like a tempting option, but it's called too late. The pre_render hooks is ideal, except for being global.

Additional context

I'm happy to work on this once we arrive at a good design. Some preliminary ideas:

class MyBlueprint < Blueprinter::Base
  # Add a few extensions to all views
  extension FooExtension, BarExtension

  view :foo do
    # add a dynamic extension to this view
    extension do
      def pre_render(obj, blueprint, view, opts)
        # do stuff
        obj
      end
    end
  end
end
ritikesh commented 4 weeks ago

Wouldn't they be able to use transformers for that?

jhollinger commented 4 weeks ago

Wouldn't they be able to use transformers for that?

@ritikesh Only in certain circumstances. Transformers run after the object has been "hashified", whereas the pre_render hooks runs before.

Also, it wouldn't surprise me if we add more extension hooks in the future. Having an extension system with N hooks that can be used globally, class-wide, and in specific views strikes me as pretty powerful. They could in theory replace both transformers and extractors.

ritikesh commented 4 weeks ago

IMO, the classes should be as simple as possible. We should consolidate all the currently available configurations and try to consolidate them to a good API. Which was the core feature of Blueprinter to begin with. Today we have a lot of default configurations, formatters along with extractors/transformers/extensions and some in-built magic with default views and fields etc. We should look at standardising some of these stuff into a more comprehensive and complete API. I had spoken about this earlier in the extensions PR as well, suggesting to remove the default formatters option in favour of the more expressive extensions. So can we also focus on this while we build around extensions?

jhollinger commented 4 weeks ago

@ritikesh I'm sold. Maybe there should be a separate issue where we outline what we'd need to add to extensions so they could fully replace date formatters, extractors, and transformers (obligatory xkcd reference). This issue would be one of those bullet points, I suppose. Once all that's added to 1.x, we could remove date formatters, extractors, and transformers in a 2.0 release.

ritikesh commented 4 weeks ago

Should we consider a discussion board for that to brainstorm?

lessthanjacob commented 4 weeks ago

Should we consider a discussion board for that to brainstorm?

💯 Let's spin up a discussion for this!

ryanmccarthypdx commented 4 weeks ago

Link to discussion: https://github.com/procore-oss/blueprinter/discussions/420