Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Replace AttributesAccessor with AttributeSet. #100

Merged
merged 1 commit into from

2 participants

@emmanuel
Collaborator

This way the methods for accessing a set of Attributes are together with those Attributes. The down side is that AttributeSet is marginally more complex. The upside is that Virtus::Extensions and Virtus::ClassMethods are simpler and more direct.

@emmanuel emmanuel Replace AttributesAccessor with AttributeSet.
This way the methods for accessing a set of
Attributes are together with those Attributes.
d606d65
@solnic
Owner

@emmanuel I can totally see the benefit coming from simplified extensions and classmethods. This doesn't change the fact I'm totally confused when I think that attribute set is now a module and a set of attributes :D I need to think about more

@emmanuel
Collaborator

Please do think about it more. I've convinced myself that this is a good idea, so I'm eager to hear other viewpoints.

I think of it like this: after this change, AttributeSet is a collection of Attribute instances, and the methods to use them. But, due to the way that modules work, these responsibilities don't interfere with each other at all. Until someone calls include attribute_set, the attribute accessor methods are totally out of the way.

Part of the reason I think this is an improvement is that, without this change, AttributeAccessor and AttributeSet are kept in sync externally, in ClassMethods and Extensions. It's not too bad now (ie., #virtus_add_attribute), but eg., removing an Attribute from an AttributeSet is currently a hassle.

@solnic
Owner

OK let's bring it in and we'll see what happens

@solnic solnic merged commit da34fc8 into solnic:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 1, 2012
  1. @emmanuel

    Replace AttributesAccessor with AttributeSet.

    emmanuel authored
    This way the methods for accessing a set of
    Attributes are together with those Attributes.
This page is out of date. Refresh to see the latest.
View
1  lib/virtus.rb
@@ -56,7 +56,6 @@ def self.extended(object)
require 'virtus/class_inclusions'
require 'virtus/module_extensions'
-require 'virtus/attributes_accessor'
require 'virtus/class_methods'
require 'virtus/instance_methods'
View
33 lib/virtus/attribute_set.rb
@@ -1,7 +1,7 @@
module Virtus
# A set of Attribute objects
- class AttributeSet
+ class AttributeSet < Module
include Enumerable
# Initialize an AttributeSet
@@ -66,6 +66,7 @@ def merge(attributes)
# @api public
def <<(attribute)
self[attribute.name] = attribute
+ attribute.define_accessor_methods(self)
self
end
@@ -110,6 +111,36 @@ def reset
self
end
+ # Defines an attribute reader method
+ #
+ # @param [Attribute] attribute
+ # @param [Symbol] method_name
+ # @param [Symbol] visibility
+ #
+ # @return [self]
+ #
+ # @api private
+ def define_reader_method(attribute, method_name, visibility)
+ define_method(method_name) { attribute.get(self) }
+ send(visibility, method_name)
+ self
+ end
+
+ # Defines an attribute writer method
+ #
+ # @param [Attribute] attribute
+ # @param [Symbol] method_name
+ # @param [Symbol] visibility
+ #
+ # @return [self]
+ #
+ # @api private
+ def define_writer_method(attribute, method_name, visibility)
+ define_method(method_name) { |value| attribute.set(self, value) }
+ send(visibility, method_name)
+ self
+ end
+
private
# Merge the attributes into the index
View
68 lib/virtus/attributes_accessor.rb
@@ -1,68 +0,0 @@
-module Virtus
-
- # Host attribute accessor methods
- class AttributesAccessor < Module
-
- # Initialize a module for hosting Attribute access methods
- #
- # @param [Symbol, String] name
- #
- # @api private
- def initialize(name)
- super()
- @name = name
- end
-
- # Defines an attribute reader method
- #
- # @param [Attribute] attribute
- # @param [Symbol] method_name
- # @param [Symbol] visibility
- #
- # @return [self]
- #
- # @api private
- def define_reader_method(attribute, method_name, visibility)
- define_method(method_name) { attribute.get(self) }
- send(visibility, method_name)
- self
- end
-
- # Defines an attribute writer method
- #
- # @param [Attribute] attribute
- # @param [Symbol] method_name
- # @param [Symbol] visibility
- #
- # @return [self]
- #
- # @api private
- def define_writer_method(attribute, method_name, visibility)
- define_method(method_name) { |value| attribute.set(self, value) }
- send(visibility, method_name)
- self
- end
-
- # The inspect value of this Module
- #
- # This provides meaningful output when inspecting the ancestors
- # of a class/module that includes this module
- #
- # @example
- #
- # class ClassWithAttributes
- # include Virtus
- # end
- #
- # mod = ClassWithAttributes.send(:virtus_setup_attributes_accessor_module)
- # mod.inspect
- #
- # @return [String]
- #
- # @api public
- def inspect
- "#{@name}::AttributesAccessor"
- end
-
- end
-end
View
16 lib/virtus/class_methods.rb
@@ -15,7 +15,7 @@ def self.extended(descendant)
super
descendant.module_eval do
extend DescendantsTracker
- virtus_setup_attributes_accessor_module
+ include attribute_set
end
end
@@ -56,18 +56,6 @@ def attributes
attribute_set
end
- protected
-
- # Set up the anonymous module which will host Attribute accessor methods
- #
- # @return [self]
- #
- # @api private
- def virtus_setup_attributes_accessor_module
- @virtus_attributes_accessor_module = AttributesAccessor.new(inspect)
- include @virtus_attributes_accessor_module
- end
-
private
# Setup descendants' own Attribute-accessor-method-hosting modules
@@ -85,7 +73,7 @@ def virtus_setup_attributes_accessor_module
# @api private
def inherited(descendant)
super
- descendant.virtus_setup_attributes_accessor_module
+ descendant.module_eval { include attribute_set }
end
# Hooks into const missing process to determine types of attributes
View
6 lib/virtus/extensions.rb
@@ -14,10 +14,9 @@ module Extensions
# @api private
def self.extended(object)
super
- object.extend(InstanceMethods)
object.instance_eval do
- @virtus_attributes_accessor_module = AttributesAccessor.new(object.class.inspect)
- extend @virtus_attributes_accessor_module
+ extend InstanceMethods
+ extend attribute_set
end
end
private_class_method :extended
@@ -51,7 +50,6 @@ def self.extended(object)
# @api public
def attribute(*args)
attribute = Attribute.build(*args)
- attribute.define_accessor_methods(@virtus_attributes_accessor_module)
virtus_add_attribute(attribute)
self
end
View
2  spec/unit/virtus/attribute_set/append_spec.rb
@@ -8,6 +8,8 @@
let(:object) { described_class.new(parent, attributes) }
let(:name) { :name }
+ before { attribute.stub(:define_accessor_methods) }
+
context 'with a new attribute' do
let(:attribute) { mock('Attribute', :name => name) }
View
4 .../attributes_accessor/define_reader_method_spec.rb → ...virtus/attribute_set/define_reader_method_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe Virtus::AttributesAccessor, '#define_reader_method' do
- subject { described_class.new('Test') }
+describe Virtus::AttributeSet, '#define_reader_method' do
+ subject { described_class.new }
let(:attribute) { mock('attribute') }
View
4 .../attributes_accessor/define_writer_method_spec.rb → ...virtus/attribute_set/define_writer_method_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe Virtus::AttributesAccessor, '#define_writer_method' do
- subject { described_class.new('Test') }
+describe Virtus::AttributeSet, '#define_writer_method' do
+ subject { described_class.new }
let(:attribute) { mock('attribute') }
View
4 spec/unit/virtus/attributes_accessor/inspect_spec.rb → spec/unit/virtus/attribute_set/inspect_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe Virtus::AttributesAccessor, '#inspect' do
+describe Virtus::AttributeSet, '#inspect' do
subject { object.inspect }
let(:object) { described_class.new('Test') }
- it { should eql('Test::AttributesAccessor') }
+ it { pending; should eql('Test::AttributeSet') }
end
View
2  spec/unit/virtus/attribute_set/merge_spec.rb
@@ -9,6 +9,8 @@
let(:name) { :name }
let(:other) { [ attribute ] }
+ before { attribute.stub(:define_accessor_methods) }
+
context 'with a new attribute' do
let(:attribute) { mock('Attribute', :name => name) }
View
4 spec/unit/virtus/attribute_set/reset_spec.rb
@@ -8,6 +8,8 @@
let(:attributes) { [ attribute ] }
let(:object) { described_class.new(parent, attributes) }
+ before { attribute.stub(:define_accessor_methods) }
+
context 'when the parent has no attributes' do
let(:parent) { described_class.new }
@@ -39,6 +41,8 @@
let(:parent) { described_class.new([ parent_attribute ]) }
let(:new_attribute) { mock('New Attribute', :name => :parent_name) }
+ before { new_attribute.stub(:define_accessor_methods) }
+
it { should equal(object) }
it 'includes changes from the parent' do
View
1  spec/unit/virtus/class_methods/attribute_spec.rb
@@ -13,6 +13,7 @@ def assert_attribute_added(klass, name, attribute_class)
attributes[name].should be_nil
subject
attribute = attributes[name]
+ attribute.should_not be_nil
attribute.name.should be(name)
attribute.class.should be(attribute_class)
end
View
6 spec/unit/virtus/class_methods/inherited_spec.rb
@@ -5,15 +5,15 @@
let(:object) { Class.new { extend Virtus::ClassMethods } }
- it 'includes an AttributesAccessor module' do
+ it 'includes an AttributeSet module' do
descendant = subject
# return the descendant's attribute accessor modules (superclass + own)
- modules = descendant.ancestors.grep(Virtus::AttributesAccessor)
+ modules = descendant.ancestors.grep(Virtus::AttributeSet)
modules.size.should be(2)
# remove the superclass' attribute accessor module
- modules -= object.ancestors.grep(Virtus::AttributesAccessor)
+ modules -= object.ancestors.grep(Virtus::AttributeSet)
# the descendant should have it's own attribute accessor module
modules.size.should be(1)
Something went wrong with that request. Please try again.