Skip to content

Commit

Permalink
Merge branch 'main' into bdl-test
Browse files Browse the repository at this point in the history
  • Loading branch information
ritikesh authored Jan 10, 2024
2 parents a1efa7c + 2060410 commit e57aca0
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lib/blueprinter/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
require_relative 'view'
require_relative 'view_collection'
require_relative 'transformer'
require_relative 'reflection'

module Blueprinter
class Base
include BaseHelpers
extend Reflection

# Specify a field or method name used as an identifier. Usually, this is
# something like :id
Expand Down
71 changes: 71 additions & 0 deletions lib/blueprinter/reflection.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# frozen_string_literal: true

module Blueprinter
#
# Public methods for reflecting on a Blueprint.
#
module Reflection
Field = Struct.new(:name, :display_name, :options)
Association = Struct.new(:name, :display_name, :blueprint, :view, :options)

#
# Returns a Hash of views keyed by name.
#
# Example:
#
# widget_view = WidgetBlueprint.reflections[:default]
# category = widget_view.associations[:category]
# category.blueprint
# => CategoryBlueprint
# category.view
# => :default
#
# @return [Hash<Symbol, Blueprinter::Reflection::View>]
#
def reflections
@reflections ||= view_collection.views.transform_values do |view|
View.new(view.name, view_collection)
end
end

#
# Represents a view within a Blueprint.
#
class View
attr_reader :name

def initialize(name, view_collection)
@name = name
@view_collection = view_collection
end

#
# Returns a Hash of fields in this view (recursive) keyed by method name.
#
# @return [Hash<Symbol, Blueprinter::Reflection::Field>]
#
def fields
@fields ||= @view_collection.fields_for(name).each_with_object({}) do |field, obj|
next if field.options[:association]

obj[field.method] = Field.new(field.method, field.name, field.options)
end
end

#
# Returns a Hash of associations in this view (recursive) keyed by method name.
#
# @return [Hash<Symbol, Blueprinter::Reflection::Association>]
#
def associations
@associations ||= @view_collection.fields_for(name).each_with_object({}) do |field, obj|
next unless field.options[:association]

blueprint = field.options.fetch(:blueprint)
view = field.options[:view] || :default
obj[field.method] = Association.new(field.method, field.name, blueprint, view, field.options)
end
end
end
end
end
102 changes: 102 additions & 0 deletions spec/units/reflection_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# frozen_string_literal: true

require 'json'

describe Blueprinter::Reflection do
let(:category_blueprint) {
Class.new(Blueprinter::Base) do
fields :id, :name
end
}

let(:part_blueprint) {
Class.new(Blueprinter::Base) do
fields :id, :name

view :extended do
field :description
end
end
}

let(:widget_blueprint) {
cat_bp = category_blueprint
part_bp = part_blueprint
Class.new(Blueprinter::Base) do
fields :id, :name
association :category, blueprint: cat_bp

view :extended do
association :parts, blueprint: part_bp, view: :extended
end

view :extended_plus do
include_view :extended
field :foo
association :foos, blueprint: part_bp
end

view :extended_plus_plus do
include_view :extended_plus
field :bar
association :bars, blueprint: part_bp
end

view :legacy do
association :parts, blueprint: part_bp, name: :pieces
end
end
}

it 'should list views' do
expect(widget_blueprint.reflections.keys.sort).to eq [
:identifier,
:default,
:extended,
:extended_plus,
:extended_plus_plus,
:legacy,
].sort
end

it 'should list fields' do
expect(part_blueprint.reflections.fetch(:extended).fields.keys.sort).to eq [
:id,
:name,
:description,
].sort
end

it 'should list fields from included views' do
expect(widget_blueprint.reflections.fetch(:extended_plus_plus).fields.keys.sort).to eq [
:id,
:name,
:foo,
:bar,
].sort
end

it 'should list associations' do
associations = widget_blueprint.reflections.fetch(:default).associations
expect(associations.keys).to eq [:category]
end

it 'should list associations from included views' do
associations = widget_blueprint.reflections.fetch(:extended_plus_plus).associations
expect(associations.keys.sort).to eq [:category, :parts, :foos, :bars].sort
end

it 'should list associations using custom names' do
associations = widget_blueprint.reflections.fetch(:legacy).associations
expect(associations.keys).to eq [:category, :parts]
expect(associations[:parts].display_name).to eq :pieces
end

it 'should get a blueprint and view from an association' do
assoc = widget_blueprint.reflections[:extended].associations[:parts]
expect(assoc.name).to eq :parts
expect(assoc.display_name).to eq :parts
expect(assoc.blueprint).to eq part_blueprint
expect(assoc.view).to eq :extended
end
end

0 comments on commit e57aca0

Please sign in to comment.