Permalink
Browse files

First round of Accessor.build refactoring

  • Loading branch information...
1 parent 5c7cbcf commit aef3fbf9b53231ff656a2e8759813407fd398dab @solnic committed Mar 10, 2013
View
@@ -84,6 +84,7 @@ def self.coercer(&block)
require 'virtus/attribute'
require 'virtus/attribute/coercer'
+require 'virtus/attribute/accessor/builder'
require 'virtus/attribute/accessor'
require 'virtus/attribute/accessor/lazy_accessor'
require 'virtus/attribute/accessor_method'
@@ -32,21 +32,8 @@ class Accessor
# @return [Accessor]
#
# @api private
- def self.build(name, type, options)
- primitive = options[:primitive]
- visibility = determine_visibility(options)
-
- reader_class = options.fetch(:reader_class) { type.reader_class(primitive, options) }
- writer_class = options.fetch(:writer_class) { type.writer_class(primitive, options) }
-
- reader_options = type.reader_options(options).update(:visibility => visibility[:reader])
- writer_options = type.writer_options(options).update(:visibility => visibility[:writer])
-
- reader = reader_class.new(name, reader_options)
- writer = writer_class.new(name, writer_options)
-
- klass = options[:lazy] ? Accessor::LazyAccessor : self
- klass.new(reader, writer)
+ def self.build(*args)
+ Builder.call(*args)
end
# Determine visibility of reader/write methods based on the options hash
@@ -0,0 +1,69 @@
+module Virtus
+ class Attribute
+ class Accessor
+
+ class Builder
+
+ def self.call(*args)
+ builder = new(*args)
+ builder.accessor
+ end
+
+ def initialize(name, type, options = {})
+ @name = name
+ @type = type
+ @options = options
+ @primitive = options[:primitive]
@dkubb
dkubb Mar 10, 2013 Collaborator

What about @primitive = options.fetch(:primitive) .. unless primitive is optional of course.

@solnic
solnic Mar 10, 2013 Owner

Thanks! Yeah it was a required option, I've set it to default to Object.

+ @visibility = determine_visibility
+ end
+
+ def accessor
+ accessor_class.new(reader, writer)
+ end
+
+ def accessor_class
+ @options[:lazy] ? Accessor::LazyAccessor : Accessor
+ end
+
+ def reader
+ reader_class.new(@name, reader_options)
+ end
+
+ def writer
+ writer_class.new(@name, writer_options)
+ end
+
+ def reader_class
+ @options.fetch(:reader_class) {
+ @type.reader_class(@primitive, @options)
+ }
+ end
+
+ def writer_class
+ @options.fetch(:writer_class) {
+ @type.writer_class(@primitive, @options)
+ }
+ end
+
+ def reader_options
+ @type.reader_options(@options).update(:visibility => @visibility[:reader])
+ end
+
+ def writer_options
+ @type.writer_options(@options).update(:visibility => @visibility[:writer])
+ end
+
+ private
+
+ def determine_visibility
+ default_accessor = @options.fetch(:accessor, :public)
+ reader_visibility = @options.fetch(:reader, default_accessor)
+ writer_visibility = @options.fetch(:writer, default_accessor)
+ { :reader => reader_visibility, :writer => writer_visibility }
+ end
+
+ end # class Builder
+
+ end # class Accessor
+ end # class Attribute
+end # module Virtus
@@ -0,0 +1,26 @@
+require 'spec_helper'
+
+describe Virtus::Attribute::Accessor::Builder, '#accessor_class' do
+ subject { object.accessor_class }
+
+ let(:object) { described_class.new('test', type, options) }
+ let(:type) { mock('attribute_type').as_null_object }
+
+ context "when :lazy is set to false" do
+ let(:options) { { :lazy => false } }
+
+ it { should be(Virtus::Attribute::Accessor) }
+ end
+
+ context "when :lazy is not set" do
+ let(:options) { {} }
+
+ it { should be(Virtus::Attribute::Accessor) }
+ end
+
+ context "when :lazy is set to true" do
+ let(:options) { { :lazy => true } }
+
+ it { should be(Virtus::Attribute::Accessor::LazyAccessor) }
+ end
+end
@@ -0,0 +1,19 @@
+require 'spec_helper'
+
+describe Virtus::Attribute::Accessor::Builder, '#accessor' do
+ subject { object.accessor }
+
+ let(:object) { described_class.new('test', type) }
+ let(:type) { mock('attribute_type') }
+ let(:reader) { mock('reader') }
+ let(:writer) { mock('writer') }
+ let(:accessor) { mock('accessor') }
+ let(:klass) { mock('accessor_class') }
+
+ before do
+ object.stub!(:reader => reader, :writer => writer, :accessor_class => klass)
+ klass.should_receive(:new).with(reader, writer).and_return(accessor)
+ end
+
+ it { should be(accessor) }
+end
@@ -0,0 +1,34 @@
+require 'spec_helper'
+
+describe Virtus::Attribute::Accessor::Builder, '.call' do
+ subject { described_class.call(name, type, options) }
+
+ let(:name) { 'test' }
+
+ let(:type) {
+ mock(
+ 'attribute_type',
+ reader_class: reader_class,
+ writer_class: writer_class
+ )
+ }
+
+ let(:options) { {} }
+ let(:reader_class) { mock('reader_class') }
+ let(:writer_class) { mock('writer_class') }
+ let(:reader) { mock('reader') }
+ let(:writer) { mock('writer') }
+
+ before do
+ type.should_receive(:reader_options).with(options).and_return({})
+ type.should_receive(:writer_options).with(options).and_return({})
+
+ reader_class.should_receive(:new).with(name, visibility: :public).and_return(reader)
+ writer_class.should_receive(:new).with(name, visibility: :public).and_return(writer)
+ end
+
+ it { should be_instance_of(Virtus::Attribute::Accessor) }
+
+ its(:reader) { should be(reader) }
+ its(:writer) { should be(writer) }
+end
@@ -0,0 +1,27 @@
+require 'spec_helper'
+
+describe Virtus::Attribute::Accessor::Builder, '#writer_class' do
+ subject { object.writer_class }
+
+ let(:object) { described_class.new('test', type, options) }
+ let(:type) { mock('attribute_type') }
+ let(:writer_class) { mock('writer_class') }
+ let(:primitive) { options[:primitive] }
+
+ context "when options provides writer_class" do
+ let(:options) { { :writer_class => writer_class } }
+
+ it { should be(writer_class) }
+ end
+
+ context "when options doesn't provide writer_class" do
+ let(:options) { {} }
+
+ before do
+ type.should_receive(:writer_class).with(primitive, options).
+ and_return(writer_class)
+ end
+
+ it { should be(writer_class) }
+ end
+end
@@ -0,0 +1,23 @@
+require 'spec_helper'
+
+describe Virtus::Attribute::Accessor::Builder, '#reader_options' do
+ subject { object.reader_options }
+
+ let(:object) { described_class.new('test', type, options) }
+ let(:type) { mock('attribute_type') }
+ let(:options) { {} }
+
+ before do
+ type.should_receive(:reader_options).with(options).and_return({})
+ end
+
+ context "when reader visibility is not set" do
+ it { should include(:visibility => :public) }
+ end
+
+ context "when reader visibility is set" do
+ let(:options) { { :reader => :private } }
+
+ it { should include(:visibility => :private) }
+ end
+end
@@ -0,0 +1,23 @@
+require 'spec_helper'
+
+describe Virtus::Attribute::Accessor::Builder, '#reader' do
+ subject { object.reader }
+
+ let(:object) { described_class.new('test', type) }
+ let(:type) { mock('attribute_type').as_null_object }
+
+ let(:reader_class) { mock('reader_class') }
+ let(:reader_opts) { mock('reader_opts') }
+ let(:reader) { mock('reader') }
+
+ before do
+ object.stub!(
+ :reader_class => reader_class,
+ :reader_options => reader_opts
+ )
+ reader_class.should_receive(:new).with('test', reader_opts).
+ and_return(reader)
+ end
+
+ it { should be(reader) }
+end
@@ -0,0 +1,27 @@
+require 'spec_helper'
+
+describe Virtus::Attribute::Accessor::Builder, '#reader_class' do
+ subject { object.reader_class }
+
+ let(:object) { described_class.new('test', type, options) }
+ let(:type) { mock('attribute_type') }
+ let(:reader_class) { mock('reader_class') }
+ let(:primitive) { options[:primitive] }
+
+ context "when options provides reader_class" do
+ let(:options) { { :reader_class => reader_class } }
+
+ it { should be(reader_class) }
+ end
+
+ context "when options doesn't provide reader_class" do
+ let(:options) { {} }
+
+ before do
+ type.should_receive(:reader_class).with(primitive, options).
+ and_return(reader_class)
+ end
+
+ it { should be(reader_class) }
+ end
+end
@@ -0,0 +1,23 @@
+require 'spec_helper'
+
+describe Virtus::Attribute::Accessor::Builder, '#writer_options' do
+ subject { object.writer_options }
+
+ let(:object) { described_class.new('test', type, options) }
+ let(:type) { mock('attribute_type') }
+ let(:options) { {} }
+
+ before do
+ type.should_receive(:writer_options).with(options).and_return({})
+ end
+
+ context "when writer visibility is not set" do
+ it { should include(:visibility => :public) }
+ end
+
+ context "when writer visibility is set" do
+ let(:options) { { :writer => :private } }
+
+ it { should include(:visibility => :private) }
+ end
+end
@@ -0,0 +1,23 @@
+require 'spec_helper'
+
+describe Virtus::Attribute::Accessor::Builder, '#writer' do
+ subject { object.writer }
+
+ let(:object) { described_class.new('test', type) }
+ let(:type) { mock('attribute_type').as_null_object }
+
+ let(:writer_class) { mock('writer_class') }
+ let(:writer_opts) { mock('writer_opts') }
+ let(:writer) { mock('writer') }
+
+ before do
+ object.stub!(
+ :writer_class => writer_class,
+ :writer_options => writer_opts
+ )
+ writer_class.should_receive(:new).with('test', writer_opts).
+ and_return(writer)
+ end
+
+ it { should be(writer) }
+end

0 comments on commit aef3fbf

Please sign in to comment.