Skip to content

Commit

Permalink
Break 'association' up into 'object' and 'collection'
Browse files Browse the repository at this point in the history
Signed-off-by: Jordan Hollinger <[email protected]>
  • Loading branch information
jhollinger committed Oct 22, 2024
1 parent 8eca9a2 commit 9527256
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 27 deletions.
1 change: 1 addition & 0 deletions lib/blueprinter/v2/association.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module V2
Association = Struct.new(
:name,
:blueprint,
:collection,
:legacy_view,
:from,
:value_proc,
Expand Down
29 changes: 27 additions & 2 deletions lib/blueprinter/v2/dsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def field(name, from: name, **options, &definition)
end

#
# Define an association.
# Define an association to a single object.
#
# @param name [Symbol] Name of the association
# @param blueprint [Class|Proc] Blueprint class to use, or one defined with a Proc
Expand All @@ -65,12 +65,37 @@ def field(name, from: name, **options, &definition)
# @yield [TODO] Generate the value from the block
# @return [Blueprinter::V2::Association]
#
def association(name, blueprint, from: name, view: nil, **options, &definition)
def object(name, blueprint, from: name, view: nil, **options, &definition)
raise ArgumentError, 'The :view argument may not be used with V2 Blueprints' if view && blueprint.is_a?(V2)

fields[name.to_sym] = Association.new(
name: name,
blueprint: blueprint,
collection: false,
legacy_view: view,
from: from,
value_proc: definition,
options: options.dup
)
end

#
# Define an association to a collection of objects.
#
# @param name [Symbol] Name of the association
# @param blueprint [Class|Proc] Blueprint class to use, or one defined with a Proc
# @param view [Symbol] Only for use with legacy (not V2) blueprints
# @param from [Symbol] Optionally specify a different method to call to get the value for "name"
# @yield [TODO] Generate the value from the block
# @return [Blueprinter::V2::Association]
#
def collection(name, blueprint, from: name, view: nil, **options, &definition)
raise ArgumentError, 'The :view argument may not be used with V2 Blueprints' if view && blueprint.is_a?(V2)

fields[name.to_sym] = Association.new(
name: name,
blueprint: blueprint,
collection: true,
legacy_view: view,
from: from,
value_proc: definition,
Expand Down
9 changes: 6 additions & 3 deletions lib/blueprinter/v2/reflection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ class View
attr_reader :name
# @return [Hash<Symbol, Blueprinter::V2::Field>] Fields defined on the view
attr_reader :fields
# @return [Hash<Symbol, Blueprinter::V2::Association>] Associations defined on the view
attr_reader :associations
# @return [Hash<Symbol, Blueprinter::V2::Association>] Associations to single objects defined on the view
attr_reader :objects
# @return [Hash<Symbol, Blueprinter::V2::Association>] Associations to collections defined on the view
attr_reader :collections


# @param blueprint [Class] A subclass of Blueprinter::V2::Base
Expand All @@ -48,7 +50,8 @@ class View
def initialize(blueprint, name)
@name = name
@fields = blueprint.fields.select { |_, f| f.is_a? Field }
@associations = blueprint.fields.select { |_, f| f.is_a? Association }
@objects = blueprint.fields.select { |_, f| f.is_a?(Association) && !f.collection }
@collections = blueprint.fields.select { |_, f| f.is_a?(Association) && f.collection }
end
end
end
Expand Down
38 changes: 20 additions & 18 deletions spec/v2/fields_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,23 @@
category_blueprint = Class.new(Blueprinter::V2::Base)
widget_blueprint = Class.new(Blueprinter::V2::Base)
blueprint = Class.new(Blueprinter::V2::Base) do
association :category, category_blueprint
association :widgets, widget_blueprint, from: :foo, if: -> { true }
association(:foo, widget_blueprint) { {foo: "bar"} }
object :category, category_blueprint
collection :widgets, widget_blueprint, from: :foo, if: -> { true }
object(:foo, widget_blueprint) { {foo: "bar"} }
end

ref = blueprint.reflections[:default]
expect(ref.associations[:category].class.name).to eq "Blueprinter::V2::Association"
expect(ref.associations[:category].name).to eq :category
expect(ref.associations[:category].from).to eq :category
expect(ref.associations[:category].blueprint).to eq category_blueprint
expect(ref.associations[:widgets].name).to eq :widgets
expect(ref.associations[:widgets].from).to eq :foo
expect(ref.associations[:widgets].blueprint).to eq widget_blueprint
expect(ref.associations[:widgets].options[:if].class.name).to eq "Proc"
expect(ref.associations[:foo].name).to eq :foo
expect(ref.associations[:foo].blueprint).to eq widget_blueprint
expect(ref.associations[:foo].value_proc.class.name).to eq "Proc"
expect(ref.objects[:category].class.name).to eq "Blueprinter::V2::Association"
expect(ref.objects[:category].name).to eq :category
expect(ref.objects[:category].from).to eq :category
expect(ref.objects[:category].blueprint).to eq category_blueprint
expect(ref.collections[:widgets].name).to eq :widgets
expect(ref.collections[:widgets].from).to eq :foo
expect(ref.collections[:widgets].blueprint).to eq widget_blueprint
expect(ref.collections[:widgets].options[:if].class.name).to eq "Proc"
expect(ref.objects[:foo].name).to eq :foo
expect(ref.objects[:foo].blueprint).to eq widget_blueprint
expect(ref.objects[:foo].value_proc.class.name).to eq "Proc"
end
end

Expand Down Expand Up @@ -97,8 +97,8 @@
blueprint = Class.new(Blueprinter::V2::Base) do
field :id
field :name
association :category, category_blueprint
association :widgets, widget_blueprint
object :category, category_blueprint
collection :widgets, widget_blueprint

view :foo do
exclude :name, :category
Expand All @@ -108,9 +108,11 @@

refs = blueprint.reflections
expect(refs[:default].fields.keys.sort).to eq %i(id name).sort
expect(refs[:default].associations.keys.sort).to eq %i(category widgets).sort
expect(refs[:default].objects.keys.sort).to eq %i(category).sort
expect(refs[:default].collections.keys.sort).to eq %i(widgets).sort
expect(refs[:foo].fields.keys.sort).to eq %i(id description).sort
expect(refs[:foo].associations.keys.sort).to eq %i(widgets).sort
expect(refs[:foo].objects.keys.sort).to eq %i().sort
expect(refs[:foo].collections.keys.sort).to eq %i(widgets).sort
end

it "should exclude specified fields and associations from partials" do
Expand Down
10 changes: 6 additions & 4 deletions spec/v2/reflection_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,20 @@
widget_blueprint = Class.new(Blueprinter::V2::Base)
blueprint = Class.new(Blueprinter::V2::Base) do
field :name
association :category, category_blueprint
object :category, category_blueprint

view :extended do
field :description
association :widgets, widget_blueprint
collection :widgets, widget_blueprint
end
end

expect(blueprint.reflections[:default].fields.keys).to eq %i(name)
expect(blueprint.reflections[:default].associations.keys).to eq %i(category)
expect(blueprint.reflections[:default].objects.keys).to eq %i(category)
expect(blueprint.reflections[:default].collections.keys).to eq %i()

expect(blueprint.reflections[:extended].fields.keys).to eq %i(name description)
expect(blueprint.reflections[:extended].associations.keys).to eq %i(category widgets)
expect(blueprint.reflections[:extended].objects.keys).to eq %i(category)
expect(blueprint.reflections[:extended].collections.keys).to eq %i(widgets)
end
end

0 comments on commit 9527256

Please sign in to comment.