From c2db5e5707d8a4b6857face92ba3e282f68ea904 Mon Sep 17 00:00:00 2001 From: Jordan Hollinger Date: Fri, 23 Aug 2024 17:34:01 -0400 Subject: [PATCH] Add partials Signed-off-by: Jordan Hollinger --- lib/blueprinter.rb | 1 + lib/blueprinter/errors.rb | 1 + lib/blueprinter/errors/unknown_partial.rb | 7 ++++ lib/blueprinter/v2.rb | 4 ++- lib/blueprinter/v2/dsl.rb | 30 ++++++++++++++++- spec/v2/partials_spec.rb | 41 +++++++++++++++++++++++ 6 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 lib/blueprinter/errors/unknown_partial.rb create mode 100644 spec/v2/partials_spec.rb diff --git a/lib/blueprinter.rb b/lib/blueprinter.rb index 330691a8..33968daf 100644 --- a/lib/blueprinter.rb +++ b/lib/blueprinter.rb @@ -8,6 +8,7 @@ module Blueprinter autoload :Extension, 'blueprinter/extension' autoload :Transformer, 'blueprinter/transformer' autoload :V2, 'blueprinter/v2' + autoload :V3, 'blueprinter/v3' class << self # @return [Configuration] diff --git a/lib/blueprinter/errors.rb b/lib/blueprinter/errors.rb index 2d4d98bb..cd79ecbc 100644 --- a/lib/blueprinter/errors.rb +++ b/lib/blueprinter/errors.rb @@ -3,6 +3,7 @@ module Blueprinter module Errors autoload :InvalidBlueprint, 'blueprinter/errors/invalid_blueprint' + autoload :UnknownPartial, 'blueprinter/errors/unknown_partial' autoload :UnknownView, 'blueprinter/errors/unknown_view' end end diff --git a/lib/blueprinter/errors/unknown_partial.rb b/lib/blueprinter/errors/unknown_partial.rb new file mode 100644 index 00000000..88aacada --- /dev/null +++ b/lib/blueprinter/errors/unknown_partial.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Blueprinter + module Errors + class UnknownPartial < Blueprinter::BlueprinterError; end + end +end diff --git a/lib/blueprinter/v2.rb b/lib/blueprinter/v2.rb index 0d4ff970..bccf937b 100644 --- a/lib/blueprinter/v2.rb +++ b/lib/blueprinter/v2.rb @@ -11,13 +11,14 @@ class V2 extend Reflection class << self - attr_accessor :views, :fields, :extensions, :options + attr_accessor :views, :fields, :partials, :extensions, :options # The fully-qualified name, e.g. "MyBlueprint", or "MyBlueprint.foo.bar" attr_accessor :blueprint_name end self.views = {} self.fields = {} + self.partials = {} self.extensions = [] self.options = Options.new(DEFAULT_OPTIONS) self.blueprint_name = name @@ -26,6 +27,7 @@ class << self def self.inherited(subclass) subclass.views = { default: subclass } subclass.fields = fields.transform_values(&:dup) + subclass.partials = partials.dup subclass.extensions = extensions.dup subclass.options = options.dup subclass.blueprint_name = subclass.name || blueprint_name diff --git a/lib/blueprinter/v2/dsl.rb b/lib/blueprinter/v2/dsl.rb index 0988de87..b35cf611 100644 --- a/lib/blueprinter/v2/dsl.rb +++ b/lib/blueprinter/v2/dsl.rb @@ -23,6 +23,30 @@ def view(name, &definition) views[name.to_sym] = view end + # + # Define a new partial. + # + # @param name [Symbol] Name of the partial to create or import + # @yield Define a new partial in the block + # + def partial(name, &definition) + partials[name.to_sym] = definition + end + + # + # Import a partial into this view. + # + # @param name [Array] One or more partial names + # + def use(*names) + names.each do |name| + if !(p = partials[name]) + raise Errors::UnknownPartial, "Partial '#{name}' could not be found in Blueprint '#{self}'. NOTE: partials must be defined before your views!" + end + class_eval(&p) + end + end + # # Define a field. # @@ -67,7 +91,11 @@ def association(name, blueprint, from: name, view: nil, **options, &definition) ) end - # Exclude parent fields/associations from inheritance + # + # Exclude parent fields and associations from this view. + # + # @param name [Array] One or more fields or associations to exclude + # def exclude(*names) unknown = [] names.each do |name| diff --git a/spec/v2/partials_spec.rb b/spec/v2/partials_spec.rb new file mode 100644 index 00000000..fe12a898 --- /dev/null +++ b/spec/v2/partials_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +describe "Blueprinter::V2 Partials" do + it "should allow a partial to be used in any view" do + blueprint = Class.new(Blueprinter::V2) do + field :name + + partial :description do + field :description + end + + view :foo do + use :description + end + + view :bar do + use :description + end + end + + expect(blueprint.reflections[:default].fields.keys).to eq %i(name) + expect(blueprint.reflections[:foo].fields.keys.sort).to eq %i( + name + description + ).sort + expect(blueprint.reflections[:bar].fields.keys.sort).to eq %i( + name + description + ).sort + end + + it "should throw an error for an invalid partial name" do + expect do + Class.new(Blueprinter::V2) do + view :foo do + use :description + end + end + end.to raise_error(Blueprinter::Errors::UnknownPartial) + end +end