-
Notifications
You must be signed in to change notification settings - Fork 110
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Jordan Hollinger <[email protected]>
- Loading branch information
1 parent
3c4fc29
commit d4100bf
Showing
5 changed files
with
176 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# frozen_string_literal: true | ||
|
||
module Blueprinter | ||
module Errors | ||
class UnknownView < Blueprinter::BlueprinterError; end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# frozen_string_literal: true | ||
|
||
module Blueprinter | ||
class V2 | ||
class << self | ||
attr_accessor :views, :fields, :extensions, :blueprint_name | ||
end | ||
|
||
self.views = {} | ||
self.fields = {} | ||
self.extensions = [] | ||
self.blueprint_name = [] | ||
|
||
# Initialize subclass | ||
def self.inherited(subclass) | ||
subclass.views = {} | ||
subclass.fields = fields.dup | ||
subclass.extensions = extensions.dup | ||
subclass.blueprint_name = subclass.name ? [subclass.name] : blueprint_name.dup | ||
end | ||
|
||
# A descriptive name for the Blueprint view, e.g. "WidgetBlueprint:extended" | ||
def self.inspect | ||
to_s | ||
end | ||
|
||
# A descriptive name for the Blueprint view, e.g. "WidgetBlueprint:extended" | ||
def self.to_s | ||
blueprint_name.join ':' | ||
end | ||
|
||
# Access a child view | ||
def self.[](view) | ||
views.fetch(view) | ||
rescue KeyError | ||
raise Blueprinter::Errors::UnknownView, "View '#{view}' could not be found in Blueprint '#{self}'" | ||
end | ||
|
||
# Define a new child view, which is a subclass of self | ||
def self.view(name, &definition) | ||
views[name] = Class.new(self) | ||
views[name].blueprint_name << name | ||
views[name].class_eval(&definition) if definition | ||
views[name] | ||
end | ||
|
||
# Define a field | ||
# rubocop:todo Lint/UnusedMethodArgument | ||
def self.field(name, options = {}) | ||
fields[name] = 'TODO' | ||
end | ||
|
||
# Define an association | ||
def self.association(name, blueprint, options = {}) | ||
fields[name] = 'TODO' | ||
end | ||
|
||
def self.render(obj, options = {}) | ||
new.render(obj, options) | ||
end | ||
|
||
def render(obj, options = {}) | ||
# TODO: call an external Render module/class, passing in self, obj, and options. | ||
# | ||
# I propose this new renderer (possibly shared with 1.x) would have an "outer" and | ||
# "inner" API. The "inner" API would be used when rendering nested Blueprints. The | ||
# "outer" API would only be called here. | ||
# | ||
# This design would allow for some render hooks to only be called ONCE per render (baring | ||
# a field/association block calling "render" again), and others to be called on every | ||
# nested Blueprint. This would fix some persistent issues with blueprinter-activerecord. | ||
end | ||
|
||
# rubocop:enable Lint/UnusedMethodArgument | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
# frozen_string_literal: true | ||
|
||
describe "Blueprinter::V2 Names" do | ||
context 'const named Blueprints' do | ||
class NamedBlueprint < Blueprinter::V2 | ||
view :extended | ||
end | ||
|
||
it 'should have a base name' do | ||
expect(NamedBlueprint.to_s).to eq "NamedBlueprint" | ||
expect(NamedBlueprint.inspect).to eq "NamedBlueprint" | ||
end | ||
|
||
it 'should find a view by name' do | ||
expect(NamedBlueprint[:extended].to_s).to eq "NamedBlueprint:extended" | ||
expect(NamedBlueprint[:extended].inspect).to eq "NamedBlueprint:extended" | ||
end | ||
|
||
it 'should raise for an invalid view name' do | ||
expect { NamedBlueprint[:wrong_name] }.to raise_error( | ||
Blueprinter::Errors::UnknownView, | ||
"View 'wrong_name' could not be found in Blueprint 'NamedBlueprint'" | ||
) | ||
end | ||
end | ||
|
||
context 'manually named Blueprints' do | ||
let(:blueprint) do | ||
Class.new(Blueprinter::V2) do | ||
blueprint_name << "MyBlueprint" | ||
view :extended | ||
end | ||
end | ||
|
||
it 'should have no base name' do | ||
expect(blueprint.to_s).to eq "MyBlueprint" | ||
expect(blueprint.inspect).to eq "MyBlueprint" | ||
end | ||
|
||
it 'should find a view by name' do | ||
expect(blueprint[:extended].to_s).to eq "MyBlueprint:extended" | ||
expect(blueprint[:extended].inspect).to eq "MyBlueprint:extended" | ||
end | ||
end | ||
|
||
context 'anonymous Blueprints' do | ||
let(:blueprint) do | ||
Class.new(Blueprinter::V2) do | ||
view :extended | ||
end | ||
end | ||
|
||
it 'should have no base name' do | ||
expect(blueprint.to_s).to eq "" | ||
expect(blueprint.inspect).to eq "" | ||
end | ||
|
||
it 'should find a view by name' do | ||
expect(blueprint[:extended].to_s).to eq "extended" | ||
expect(blueprint[:extended].inspect).to eq "extended" | ||
end | ||
end | ||
|
||
context 'deeply nested Blueprints' do | ||
let(:blueprint) do | ||
Class.new(Blueprinter::V2) do | ||
blueprint_name << "MyBlueprint" | ||
|
||
view :foo do | ||
view :bar do | ||
view :zorp | ||
end | ||
end | ||
end | ||
end | ||
|
||
it 'should find deeply nested names' do | ||
expect(blueprint.to_s).to eq "MyBlueprint" | ||
expect(blueprint.inspect).to eq "MyBlueprint" | ||
|
||
expect(blueprint[:foo].to_s).to eq "MyBlueprint:foo" | ||
expect(blueprint[:foo].inspect).to eq "MyBlueprint:foo" | ||
|
||
expect(blueprint[:foo][:bar].to_s).to eq "MyBlueprint:foo:bar" | ||
expect(blueprint[:foo][:bar].inspect).to eq "MyBlueprint:foo:bar" | ||
|
||
expect(blueprint[:foo][:bar][:zorp].to_s).to eq "MyBlueprint:foo:bar:zorp" | ||
expect(blueprint[:foo][:bar][:zorp].inspect).to eq "MyBlueprint:foo:bar:zorp" | ||
end | ||
end | ||
end |