This repository has been archived by the owner on Nov 28, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from tricycle/ar-entity-builder
Add ActiveRecord to Dry::Struct Entity builder
- Loading branch information
Showing
3 changed files
with
122 additions
and
1 deletion.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
2.4.2 | ||
2.5.1 |
50 changes: 50 additions & 0 deletions
50
lib/clean_architecture/builders/abstract_active_record_entity_builder.rb
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,50 @@ | ||
# frozen_string_literal: true | ||
|
||
module CleanArchitecture | ||
module Builders | ||
# Helps to take an instance of an AR model and wrap it up in the given Entity | ||
# Any columns from the AR model that do not directly map to an attribute on the Entity | ||
# can be specified by overriding #attributes_for_entity. | ||
class AbstractActiveRecordEntityBuilder | ||
# @param [Class] A Dry::Struct based entity that this builder will construct instances of | ||
def self.acts_as_builder_for_entity(entity_class) | ||
define_method :entity_class do | ||
entity_class | ||
end | ||
|
||
private :entity_class | ||
end | ||
|
||
# @param [ActiveRecord::Base] An ActiveRecord model to map to the entity | ||
def initialize(ar_model_instance) | ||
@ar_model_instance = ar_model_instance | ||
end | ||
|
||
def build | ||
entity_class.new(all_attributes_for_entity) | ||
end | ||
|
||
private | ||
|
||
attr_reader :ar_model_instance | ||
|
||
def entity_attribute_names | ||
@entity_attributes ||= entity_class.schema.keys | ||
end | ||
|
||
def ar_attributes_for_entity | ||
attributes_for_entity = @ar_model_instance.attributes | ||
symbolized_attributes_for_entity = Hash[attributes_for_entity.map{|(key, value)| [key.to_sym, value]}] | ||
symbolized_attributes_for_entity.slice(*entity_attribute_names) | ||
end | ||
|
||
def attributes_for_entity | ||
{} | ||
end | ||
|
||
def all_attributes_for_entity | ||
ar_attributes_for_entity.merge(attributes_for_entity) | ||
end | ||
end | ||
end | ||
end |
71 changes: 71 additions & 0 deletions
71
spec/lib/clean_architecture/builders/abstract_active_record_entity_builder_spec.rb
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,71 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'clean_architecture/builders/abstract_active_record_entity_builder' | ||
|
||
module CleanArchitecture | ||
module Builders | ||
describe AbstractActiveRecordEntityBuilder do | ||
class ExampleModel | ||
def age | ||
25 | ||
end | ||
|
||
def attributes | ||
{ | ||
'forename' => 'Samuel', | ||
'surname' => 'Giles', | ||
'age' => 25 | ||
} | ||
end | ||
end | ||
|
||
class ExampleEntitySchema | ||
def keys | ||
[:forename, :surname, :years_on_planet_earth] | ||
end | ||
end | ||
|
||
class ExampleEntity | ||
def initialize(attributes) | ||
@attributes = attributes | ||
end | ||
|
||
def self.schema | ||
ExampleEntitySchema.new | ||
end | ||
end | ||
|
||
class ExampleBuilder < AbstractActiveRecordEntityBuilder | ||
acts_as_builder_for_entity ExampleEntity | ||
|
||
def attributes_for_entity | ||
{ | ||
years_on_planet_earth: ar_model_instance.age | ||
} | ||
end | ||
end | ||
|
||
let(:builder) { ExampleBuilder.new(ar_model_instance) } | ||
let(:ar_model_instance) { ExampleModel.new } | ||
|
||
describe '#build' do | ||
subject(:build) { builder.build } | ||
|
||
let(:example_entity) { instance_double(ExampleEntity) } | ||
|
||
before do | ||
expect(ExampleEntity) | ||
.to receive(:new) | ||
.with( | ||
forename: 'Samuel', | ||
surname: 'Giles', | ||
years_on_planet_earth: 25 | ||
) | ||
.and_return(example_entity) | ||
end | ||
|
||
it { is_expected.to eq example_entity } | ||
end | ||
end | ||
end | ||
end |