Skip to content

Commit

Permalink
use virtus class_options
Browse files Browse the repository at this point in the history
This is the implementation of virtus with a combined getter and setter.
  • Loading branch information
Gibheer committed Jan 28, 2013
1 parent 9f429ac commit 90eccbb
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 17 deletions.
110 changes: 97 additions & 13 deletions lib/class_options/options.rb
Original file line number Diff line number Diff line change
@@ -1,24 +1,108 @@
module ClassOptions
module Options
def options(*names)
names.each do |option|
create_option(option)
# Returns default options hash for a given attribute class
#
# @example
# Virtus::Attribute::String.options
# # => {:primitive => String}
#
# @return [Hash]
# a hash of default option values
#
# @api public
def options
accepted_options.each_with_object({}) do |option_name, options|
option_value = send(option_name)
options[option_name] = option_value unless option_value.nil?
end
end

protected
# Returns an array of valid options
#
# @example
# Virtus::Attribute::String.accepted_options
# # => [:primitive, :accessor, :reader, :writer]
#
# @return [Array]
# the array of valid option names
#
# @api public
def accepted_options
@accepted_options ||= []
end

# Defines which options are valid for a given attribute class
#
# @example
# class MyAttribute < Virtus::Attribute::Object
# accept_options :foo, :bar
# end
#
# @return [self]
#
# @api public
def accept_options(*new_options)
add_accepted_options(new_options)
new_options.each { |option| define_option_method(option) }
# descendants.each { |descendant| descendant.add_accepted_options(new_options) }
self
end

def create_option(option)
protected

# Adds a reader/writer method for the give option name
#
# @return [undefined]
#
# @api private
def define_option_method(option)
class_eval <<-RUBY, __FILE__, __LINE__ + 1
def self.#{option}=(value = ClassOptions::Undefined)
@#{option} = value
self
end
def self.#{option}
@#{option} ||= ClassOptions::Undefined
end
def self.#{option}(value = Undefined) # def self.primitive(value = Undefined)
return @#{option} || Undefined if value.equal?(Undefined) # return @primitive if value.equal?(Undefined)
@#{option} = value # @primitive = value
self # self
end # end
RUBY
end

# Sets default options
#
# @param [#each] new_options
# options to be set
#
# @return [self]
#
# @api private
def set_options(new_options)
new_options.each { |pair| send(*pair) }
self
end

# Adds new options that an attribute class can accept
#
# @param [#to_ary] new_options
# new options to be added
#
# @return [self]
#
# @api private
def add_accepted_options(new_options)
accepted_options.concat(new_options)
self
end

private

# Adds descendant to descendants array and inherits default options
#
# @param [Class] descendant
#
# @return [undefined]
#
# @api private
def inherited(descendant)
super
descendant.add_accepted_options(accepted_options).set_options(options)
end
end
end
44 changes: 40 additions & 4 deletions spec/unit/class_options/options/options_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@

shared_examples_for 'an option' do
it { should respond_to(function) } # check getter
it { should respond_to(function + '=') } # check setter

it 'saves the option' do
subject.send(function + '=', value)
subject.send(function, value)
expect(subject.send(function)).to be(value)
end

Expand All @@ -23,7 +22,7 @@
let(:testclass) do
Class.new do
extend ClassOptions::Options
options :bar
accept_options :bar
end
end

Expand All @@ -34,10 +33,47 @@
let(:testclass) do
Class.new do
extend ClassOptions::Options
options :foo, :bar
accept_options :foo, :bar
end
end

it_behaves_like 'an option'
end

context 'with instances' do
let(:testclass) do
Class.new do
extend ClassOptions::Options
accept_options :foo

def initialize
@foo = self.class.foo
end
attr_reader :foo
end
end

it "gets the value from the class" do
testclass.foo(23)
t = testclass.new
expect(t.foo).to be(23)
end
end

context 'with inheritance' do
let(:primclass) do
Class.new do
extend ClassOptions::Options
accept_options :foo
end
end
let(:testclass) do
Class.new(primclass) do
end
end
it "gets the value from the inherited class" do
primclass.foo(23)
expect(testclass.foo).to be(23)
end
end
end

0 comments on commit 90eccbb

Please sign in to comment.