1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Implement mattr_acessor :default option

This commit is contained in:
Genadi Samokovarov 2017-05-30 16:16:19 +03:00
parent ab4f811d09
commit a5b0c60714
3 changed files with 65 additions and 25 deletions

View file

@ -1,3 +1,12 @@
* Add default option to module and class attribute accessors.
mattr_accessor :settings, default: {}
Works for `mattr_reader`, `mattr_writer`, `cattr_accessor`, `cattr_reader`,
and `cattr_writer` as well.
*Genadi Samokovarov*
* Add `Date#prev_occurring` and `Date#next_occurring` to return specified next/previous occurring day of week. * Add `Date#prev_occurring` and `Date#next_occurring` to return specified next/previous occurring day of week.
*Shota Iguchi* *Shota Iguchi*

View file

@ -38,13 +38,10 @@ class Module
# #
# Person.new.hair_colors # => NoMethodError # Person.new.hair_colors # => NoMethodError
# #
# # You can set a default value for the attribute.
# Also, you can pass a block to set up the attribute with a default value.
# #
# module HairColors # module HairColors
# mattr_reader :hair_colors do # mattr_reader :hair_colors, default: [:brown, :black, :blonde, :red]
# [:brown, :black, :blonde, :red]
# end
# end # end
# #
# class Person # class Person
@ -52,8 +49,7 @@ class Module
# end # end
# #
# Person.new.hair_colors # => [:brown, :black, :blonde, :red] # Person.new.hair_colors # => [:brown, :black, :blonde, :red]
def mattr_reader(*syms) def mattr_reader(*syms, instance_reader: true, instance_accessor: true, default: nil)
options = syms.extract_options!
syms.each do |sym| syms.each do |sym|
raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym) raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym)
class_eval(<<-EOS, __FILE__, __LINE__ + 1) class_eval(<<-EOS, __FILE__, __LINE__ + 1)
@ -64,14 +60,16 @@ class Module
end end
EOS EOS
unless options[:instance_reader] == false || options[:instance_accessor] == false if instance_reader && instance_accessor
class_eval(<<-EOS, __FILE__, __LINE__ + 1) class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def #{sym} def #{sym}
@@#{sym} @@#{sym}
end end
EOS EOS
end end
class_variable_set("@@#{sym}", yield) if block_given?
sym_default_value = (block_given? && default.nil?) ? yield : default
class_variable_set("@@#{sym}", sym_default_value) unless sym_default_value.nil?
end end
end end
alias :cattr_reader :mattr_reader alias :cattr_reader :mattr_reader
@ -107,12 +105,10 @@ class Module
# #
# Person.new.hair_colors = [:blonde, :red] # => NoMethodError # Person.new.hair_colors = [:blonde, :red] # => NoMethodError
# #
# Also, you can pass a block to set up the attribute with a default value. # You can set a default value for the attribute.
# #
# module HairColors # module HairColors
# mattr_writer :hair_colors do # mattr_writer :hair_colors, default: [:brown, :black, :blonde, :red]
# [:brown, :black, :blonde, :red]
# end
# end # end
# #
# class Person # class Person
@ -120,8 +116,7 @@ class Module
# end # end
# #
# Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red] # Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
def mattr_writer(*syms) def mattr_writer(*syms, instance_writer: true, instance_accessor: true, default: nil)
options = syms.extract_options!
syms.each do |sym| syms.each do |sym|
raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym) raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym)
class_eval(<<-EOS, __FILE__, __LINE__ + 1) class_eval(<<-EOS, __FILE__, __LINE__ + 1)
@ -132,14 +127,16 @@ class Module
end end
EOS EOS
unless options[:instance_writer] == false || options[:instance_accessor] == false if instance_writer && instance_accessor
class_eval(<<-EOS, __FILE__, __LINE__ + 1) class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def #{sym}=(obj) def #{sym}=(obj)
@@#{sym} = obj @@#{sym} = obj
end end
EOS EOS
end end
send("#{sym}=", yield) if block_given?
sym_default_value = (block_given? && default.nil?) ? yield : default
send("#{sym}=", sym_default_value) unless sym_default_value.nil?
end end
end end
alias :cattr_writer :mattr_writer alias :cattr_writer :mattr_writer
@ -197,12 +194,10 @@ class Module
# Person.new.hair_colors = [:brown] # => NoMethodError # Person.new.hair_colors = [:brown] # => NoMethodError
# Person.new.hair_colors # => NoMethodError # Person.new.hair_colors # => NoMethodError
# #
# Also you can pass a block to set up the attribute with a default value. # You can set a default value for the attribute.
# #
# module HairColors # module HairColors
# mattr_accessor :hair_colors do # mattr_accessor :hair_colors, default: [:brown, :black, :blonde, :red]
# [:brown, :black, :blonde, :red]
# end
# end # end
# #
# class Person # class Person
@ -210,9 +205,9 @@ class Module
# end # end
# #
# Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red] # Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
def mattr_accessor(*syms, &blk) def mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil, &blk)
mattr_reader(*syms, &blk) mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor, default: default, &blk)
mattr_writer(*syms) mattr_writer(*syms, instance_writer: instance_writer, instance_accessor: instance_accessor, default: default)
end end
alias :cattr_accessor :mattr_accessor alias :cattr_accessor :mattr_accessor
end end

View file

@ -12,7 +12,14 @@ class ModuleAttributeAccessorTest < ActiveSupport::TestCase
cattr_accessor(:defa) { "default_accessor_value" } cattr_accessor(:defa) { "default_accessor_value" }
cattr_reader(:defr) { "default_reader_value" } cattr_reader(:defr) { "default_reader_value" }
cattr_writer(:defw) { "default_writer_value" } cattr_writer(:defw) { "default_writer_value" }
cattr_accessor(:deff) { false }
cattr_accessor(:quux) { :quux } cattr_accessor(:quux) { :quux }
cattr_accessor :def_accessor, default: "default_accessor_value"
cattr_reader :def_reader, default: "default_reader_value"
cattr_writer :def_writer, default: "default_writer_value"
cattr_accessor :def_false, default: false
cattr_accessor(:def_priority, default: false) { :no_priority }
end end
@class = Class.new @class = Class.new
@class.instance_eval { include m } @class.instance_eval { include m }
@ -24,6 +31,21 @@ class ModuleAttributeAccessorTest < ActiveSupport::TestCase
assert_nil @object.foo assert_nil @object.foo
end end
def test_mattr_default_keyword_arguments
assert_equal "default_accessor_value", @module.def_accessor
assert_equal "default_reader_value", @module.def_reader
assert_equal "default_writer_value", @module.class_variable_get(:@@def_writer)
end
def test_mattr_can_default_to_false
assert_equal false, @module.def_false
assert_equal false, @module.deff
end
def test_mattr_default_priority
assert_equal false, @module.def_priority
end
def test_should_set_mattr_value def test_should_set_mattr_value
@module.foo = :test @module.foo = :test
assert_equal :test, @object.foo assert_equal :test, @object.foo
@ -91,9 +113,23 @@ class ModuleAttributeAccessorTest < ActiveSupport::TestCase
assert_equal "default_writer_value", @module.class_variable_get("@@defw") assert_equal "default_writer_value", @module.class_variable_get("@@defw")
end end
def test_should_not_invoke_default_value_block_multiple_times def test_method_invocation_should_not_invoke_the_default_block
count = 0 count = 0
@module.cattr_accessor(:defcount) { count += 1 } @module.cattr_accessor(:defcount) { count += 1 }
assert_equal 1, count assert_equal 1, count
assert_no_difference "count" do
@module.defcount
end
end
def test_declaring_multiple_attributes_at_once_invokes_the_block_multiple_times
count = 0
@module.cattr_accessor(:defn1, :defn2) { count += 1 }
assert_equal 1, @module.defn1
assert_equal 2, @module.defn2
end end
end end