Skip to content

Commit

Permalink
Renderer - wip
Browse files Browse the repository at this point in the history
Signed-off-by: Jordan Hollinger <[email protected]>
  • Loading branch information
jhollinger committed Oct 26, 2024
1 parent 25f7964 commit 9bcc80a
Show file tree
Hide file tree
Showing 48 changed files with 2,938 additions and 228 deletions.
1 change: 1 addition & 0 deletions lib/blueprinter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module Blueprinter
autoload :Configuration, 'blueprinter/configuration'
autoload :Errors, 'blueprinter/errors'
autoload :Extension, 'blueprinter/extension'
autoload :Hooks, 'blueprinter/hooks'
autoload :Transformer, 'blueprinter/transformer'
autoload :V2, 'blueprinter/v2'

Expand Down
2 changes: 1 addition & 1 deletion lib/blueprinter/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ def self.render_as_json(object, options = {})
def self.prepare(object, view_name:, local_options:, root: nil, meta: nil)
raise BlueprinterError, "View '#{view_name}' is not defined" unless view_collection.view? view_name

object = Blueprinter.configuration.extensions.pre_render(object, self, view_name, local_options)
object = Blueprinter.configuration.hooks.reduce(:pre_render, object) { |val| [val, self, view_name, local_options] }
data = prepare_data(object, view_name, local_options)
prepend_root_and_meta(data, root, meta)
end
Expand Down
10 changes: 7 additions & 3 deletions lib/blueprinter/configuration.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

require 'json'
require 'blueprinter/extensions'
require 'blueprinter/hooks'
require 'blueprinter/extractors/auto_extractor'

module Blueprinter
Expand All @@ -27,11 +27,15 @@ def initialize
end

def extensions
@extensions ||= Extensions.new
@extensions ||= []
end

def extensions=(list)
@extensions = Extensions.new(list)
@extensions = list
end

def hooks
@hooks ||= Blueprinter::Hooks.new(extensions)
end

def array_like_classes
Expand Down
181 changes: 179 additions & 2 deletions lib/blueprinter/extension.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,188 @@

module Blueprinter
#
# Base class for all extensions. All extension methods are implemented as no-ops.
# Base class for all extensions.
#
# V2 hook call order:
# - collection? (skipped when using render_object/render_collection)
# - input_object | input_collection
# - each_input
# - field_value
# - formatters
# - exclude_field?
# - object_value
# - exclude_object?
# - collection_value
# - exclude_collection?
# - each_output
# - output_object | output_collection
#
# V1 hook call order:
# - pre_render
#
class Extension
class << self
attr_accessor :formatters
end

def self.inherited(ext)
ext.formatters = {}
end

#
# Add a formatter for instances of the given class.
#
# Example:
# class MyExtension < Blueprinter::Extension
# format(Time) { |context| context.value.iso8601 }
# format Date, :date_str
#
# def date_str(context)
# context.value.iso8601
# end
# end
#
# @param klass [Class] The class of objects to format
# @param formatter_method [Symbol] Name of a public instance method to call for formatting
# @yield Do formatting in the block instead
#
def self.format(klass, formatter_method = nil, &formatter_block)
formatters[klass] = formatter_method || formatter_block
end

#
# Returns true if the given object should be considered a collection.
#
# @param [Object]
# @return [Boolean]
#
def collection?(_object)
false
end

#
# Modify or replace the object passed to render/render_object.
#
# @param context [Blueprinter::V2::Serializer::Context]
# @return [Object]
#
def input_object(context)
context.object
end


#
# Modify or replace the collection passed to render/render_collection.
#
# @param context [Blueprinter::V2::Serializer::Context]
# @return [Object]
#
def input_collection(context)
context.object
end

#
# Modify or replace the object result before final render (e.g. to JSON).
#
# @param context [Blueprinter::V2::Serializer::Context]
# @return [Object]
#
def output_object(context)
context.value
end

#
# Modify or replace the collection result before final render (e.g. to JSON).
#
# @param context [Blueprinter::V2::Serializer::Context]
# @return [Object]
#
def output_collection(context)
context.value
end

#
# Modify or replace the object that's passed into each Blueprint.
#
# @param context [Blueprinter::V2::Serializer::Context]
# @return [Object]
#
def each_input(context)
context.object
end

#
# Modify or replace the output from each Blueprint.
#
# @param context [Blueprinter::V2::Serializer::Context]
# @return [Object]
#
def each_output(context)
context.value
end

#
# Modify or replace the value used for the field.
#
# @param context [Blueprinter::V2::Serializer::Context]
# @return [Object]
#
def field_value(context)
context.value
end

#
# Modify or replace the value used for the object.
#
# @param context [Blueprinter::V2::Serializer::Context]
# @return [Object]
#
def object_value(context)
context.value
end

#
# Modify or replace the value used for the collection.
#
# @param context [Blueprinter::V2::Serializer::Context]
# @return [Object]
#
def collection_value(context)
context.value
end

#
# Return true to exclude this field from the result.
#
# @param _context [Blueprinter::V2::Serializer::Context]
# @return [Boolean]
#
def exclude_field?(_context)
false
end

#
# Return true to exclude this object from the result.
#
# @param _context [Blueprinter::V2::Serializer::Context]
# @return [Boolean]
#
def exclude_object?(_context)
false
end

#
# Return true to exclude this collection from the result.
#
# @param _context [Blueprinter::V2::Serializer::Context]
# @return [Boolean]
#
def exclude_collection?(_context)
false
end

#
# Called eary during "render", this method receives the object to be rendered and
# Called eary during "render" in V1, this method receives the object to be rendered and
# may return a modified (or new) object to be rendered.
#
# @param object [Object] The object to be rendered
Expand Down
37 changes: 0 additions & 37 deletions lib/blueprinter/extensions.rb

This file was deleted.

40 changes: 40 additions & 0 deletions lib/blueprinter/hooks.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# frozen_string_literal: true

module Blueprinter
# An interface for running extension hooks
class Hooks
def initialize(extensions)
@hooks = Extension.public_instance_methods(false).each_with_object({}) do |hook, acc|
acc[hook] = extensions.
select { |ext| ext.class.public_instance_methods(false).include? hook }.
map { |ext| ext.public_method(hook) }
end
end

#
# Return true if any of "hook" returns truthy.
#
# @param hook [Symbol] Name of hook to call
# @return [Boolean]
#
def any?(hook, *args)
@hooks.fetch(hook).any? { |h| h.call(*args) }
end

#
# Call the hooks in series, passing the output of one to the block, which returns the args for the next.
#
# If the hook requires multiple arguments, the block should return an array.
#
# @param hook [Symbol] Name of hook to call
# @param initial_value [Object] The starting value for the block
# @return [Object] The last hook's return value
#
def reduce(hook, initial_value)
@hooks.fetch(hook).reduce(initial_value) do |val, h|
args = yield val
args.is_a?(Array) ? h.call(*args) : h.call(args)
end
end
end
end
17 changes: 16 additions & 1 deletion lib/blueprinter/v2.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
# frozen_string_literal: true

require 'blueprinter/v2/base'
require 'blueprinter/v2/fields'

module Blueprinter
module V2
autoload :Base, 'blueprinter/v2/base'
autoload :DSL, 'blueprinter/v2/dsl'
autoload :Extensions, 'blueprinter/v2/extensions'
autoload :Extractor, 'blueprinter/v2/extractor'
autoload :Formatter, 'blueprinter/v2/formatter'
autoload :InstanceCache, 'blueprinter/v2/instance_cache'
autoload :Reflection, 'blueprinter/v2/reflection'
autoload :Render, 'blueprinter/v2/render'
autoload :Serializer, 'blueprinter/v2/serializer'
autoload :ViewBuilder, 'blueprinter/v2/view_builder'
end
end
16 changes: 0 additions & 16 deletions lib/blueprinter/v2/association.rb

This file was deleted.

Loading

0 comments on commit 9bcc80a

Please sign in to comment.