Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for defining default transformer #222

Merged
merged 5 commits into from
Jul 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,25 @@ class UserBlueprint < Blueprinter::Base
end
```

#### Global Transforms

You can also specify global default transformers. Create one or more transformer classes extending from `Blueprinter::Transformer` and set the `default_transformers` configuration
```ruby
class LowerCamelTransformer < Blueprinter::Transformer
def transform(hash, _object, _options)
hash.transform_keys! { |key| key.to_s.camelize(:lower).to_sym }
end
end
```

```ruby
Blueprinter.configure do |config|
config.default_transformers = [LowerCamelTransformer]
end
```

**Note: Any transforms specified on a per-blueprint or per-view level will override the `default_transformers` in the configuration.**

---
</details>

Expand Down
3 changes: 2 additions & 1 deletion lib/blueprinter/configuration.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module Blueprinter
class Configuration
attr_accessor :association_default, :datetime_format, :field_default, :generator, :if, :method, :sort_fields_by, :unless, :extractor_default
attr_accessor :association_default, :datetime_format, :field_default, :generator, :if, :method, :sort_fields_by, :unless, :extractor_default, :default_transformers

VALID_CALLABLES = %i(if unless).freeze

Expand All @@ -14,6 +14,7 @@ def initialize
@sort_fields_by = :name_asc
@unless = nil
@extractor_default = AutoExtractor
@default_transformers = []
end

def jsonify(blob)
Expand Down
16 changes: 10 additions & 6 deletions lib/blueprinter/view.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,22 @@ module Blueprinter
# @api private
DefinitionPlaceholder = Struct.new :name, :view?
class View
attr_reader :excluded_field_names, :fields, :included_view_names, :name, :transformers, :definition_order
attr_reader :excluded_field_names, :fields, :included_view_names, :name, :view_transformers, :definition_order

def initialize(name, fields: {}, included_view_names: [], excluded_view_names: [],transformers: [])
def initialize(name, fields: {}, included_view_names: [], excluded_view_names: [], transformers: [])
@name = name
@fields = fields
@included_view_names = included_view_names
@excluded_field_names = excluded_view_names
@transformers = transformers
@view_transformers = transformers
@definition_order = []
@sort_by_definition = Blueprinter.configuration.sort_fields_by.eql?(:definition)
end

def transformers
view_transformers.empty? ? Blueprinter.configuration.default_transformers : view_transformers
end

def track_definition_order(method, is_view = true)
if @sort_by_definition
@definition_order << DefinitionPlaceholder.new(method, is_view)
Expand All @@ -33,8 +37,8 @@ def inherit(view)
exclude_field(field_name)
end

view.transformers.each do |transformer|
self.add_transformer(transformer)
view.view_transformers.each do |transformer|
add_transformer(transformer)
end
end

Expand All @@ -61,7 +65,7 @@ def exclude_fields(field_names)
end

def add_transformer(custom_transformer)
transformers << custom_transformer
view_transformers << custom_transformer
end

def <<(field)
Expand Down
29 changes: 29 additions & 0 deletions spec/integrations/shared/base_render_examples.rb
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,35 @@ def transform(result_hash, object, options={})
it('returns json with values derived from options') { should eq(result) }
end

context 'Given blueprint has a transformer with a default configured' do
let(:default_transform) do
UpcaseKeysTransformer = Class.new(Blueprinter::Transformer) do
def transform(hash, _object, _options)
hash.transform_keys! { |key| key.to_s.upcase.to_sym }
end
end
end
before do
Blueprinter.configure { |config| config.default_transformers = [default_transform] }
end
after { reset_blueprinter_config! }
subject { blueprint.render(obj) }
let(:result) { '{"id":' + obj_id + ',"full_name":"Meg Ryan"}' }
let(:blueprint) do
DynamicFieldsTransformer = Class.new(Blueprinter::Transformer) do
def transform(result_hash, object, options={})
dynamic_fields = (object.is_a? Hash) ? object[:dynamic_fields] : object.dynamic_fields
result_hash.merge!(dynamic_fields)
end
end
Class.new(Blueprinter::Base) do
identifier :id
transform DynamicFieldsTransformer
end
end
it('overrides the configured default transformer') { should eq(result) }
end

context "Ordering of fields from inside a view by definition" do
before { Blueprinter.configure { |config| config.sort_fields_by = :definition } }
after { reset_blueprinter_config! }
Expand Down
7 changes: 7 additions & 0 deletions spec/units/configuration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
let(:extractor) do
class FoodDehydrator < Blueprinter::AutoExtractor; end
end
let(:transform) do
class UpcaseTransform < Blueprinter::Transformer; end
end

it 'should set the `generator`' do
Blueprinter.configure { |config| config.generator = Oj }
Expand Down Expand Up @@ -71,6 +74,10 @@ class FoodDehydrator < Blueprinter::AutoExtractor; end
expect(Blueprinter.configuration.extractor_default).to eq(Blueprinter::AutoExtractor)
end

it 'should set the `default_transformers` option' do
Blueprinter.configure { |config| config.default_transformers = [transform] }
expect(Blueprinter.configuration.default_transformers).to eq([transform])
end
end

describe "::Configuration" do
Expand Down
39 changes: 35 additions & 4 deletions spec/units/view_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,16 @@
end
end

describe '#exclude_fields(:view_name)' do
it 'should return [:view_name]' do
describe '#exclude_fields(:view_name)' do
it 'should return [:view_name]' do
expect(view.exclude_fields([:last_name,:middle_name])).to eq([:last_name,:middle_name])
end
it 'should set #excluded_field_names to [:view_name]' do
it 'should set #excluded_field_names to [:view_name]' do
view.exclude_fields([:last_name,:middle_name])
expect(view.excluded_field_names).to eq([:last_name,:middle_name])
end
end

describe '#<<(field)' do
context 'Given a field that does not exist' do
it('should return field') { expect(view << field).to eq(field) }
Expand Down Expand Up @@ -76,6 +76,37 @@
end
end
end

context 'with default transform' do
let(:default_transform) do
class DefaultTransform < Blueprinter::Transformer; end
DefaultTransform
end
let(:override_transform) do
class OverrideTransform < Blueprinter::Transformer; end
OverrideTransform
end
let(:view_with_default_transform) do
Blueprinter::View.new('View with default transform')
end
let(:view_with_override_transform) do
Blueprinter::View.new('View with override transform', transformers: [override_transform])
end

before do
Blueprinter.configure { |config| config.default_transformers = [default_transform] }
end

describe '#transformers' do
it 'should return the default transformers' do
expect(view_with_default_transform.transformers).to eq([default_transform])
end

it 'should allow for overriding the default transformers' do
expect(view_with_override_transform.transformers).to eq([override_transform])
end
end
end
end

class MockField
Expand Down