2017-07-16 13:11:16 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2016-08-06 12:38:23 -04:00
|
|
|
require "cases/helper"
|
2009-10-07 10:05:54 -04:00
|
|
|
|
|
|
|
class ModelWithAttributes
|
|
|
|
include ActiveModel::AttributeMethods
|
2010-08-14 01:13:00 -04:00
|
|
|
|
2011-03-16 20:08:02 -04:00
|
|
|
class << self
|
|
|
|
define_method(:bar) do
|
2016-08-06 12:38:23 -04:00
|
|
|
"original bar"
|
2011-03-16 20:08:02 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-10-07 10:06:54 -04:00
|
|
|
def attributes
|
2016-08-06 12:38:23 -04:00
|
|
|
{ foo: "value of foo", baz: "value of baz" }
|
2009-10-07 10:06:54 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
def attribute(name)
|
|
|
|
attributes[name.to_sym]
|
|
|
|
end
|
2009-10-07 10:05:54 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
class ModelWithAttributes2
|
|
|
|
include ActiveModel::AttributeMethods
|
2010-08-14 01:13:00 -04:00
|
|
|
|
2011-09-04 17:07:07 -04:00
|
|
|
attr_accessor :attributes
|
|
|
|
|
2020-01-20 10:34:06 -05:00
|
|
|
attribute_method_suffix "_test", "_kw"
|
2011-09-04 17:07:07 -04:00
|
|
|
|
|
|
|
private
|
|
|
|
def attribute(name)
|
|
|
|
attributes[name.to_s]
|
|
|
|
end
|
|
|
|
|
2020-01-20 10:16:02 -05:00
|
|
|
def attribute_test(name, attrs = {})
|
|
|
|
attrs[name] = attribute(name)
|
|
|
|
end
|
2011-09-12 17:12:12 -04:00
|
|
|
|
2020-01-20 10:34:06 -05:00
|
|
|
def attribute_kw(name, kw: 1)
|
|
|
|
attribute(name)
|
|
|
|
end
|
|
|
|
|
2011-09-12 17:12:12 -04:00
|
|
|
def private_method
|
|
|
|
"<3 <3"
|
|
|
|
end
|
|
|
|
|
|
|
|
protected
|
|
|
|
def protected_method
|
|
|
|
"O_o O_o"
|
|
|
|
end
|
2009-10-07 10:05:54 -04:00
|
|
|
end
|
|
|
|
|
2011-02-03 13:46:03 -05:00
|
|
|
class ModelWithAttributesWithSpaces
|
|
|
|
include ActiveModel::AttributeMethods
|
|
|
|
|
|
|
|
def attributes
|
2016-08-16 03:30:11 -04:00
|
|
|
{ 'foo bar': "value of foo bar" }
|
2011-02-03 13:46:03 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
def attribute(name)
|
|
|
|
attributes[name.to_sym]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-03-16 18:17:47 -04:00
|
|
|
class ModelWithWeirdNamesAttributes
|
|
|
|
include ActiveModel::AttributeMethods
|
|
|
|
|
2011-03-16 18:31:57 -04:00
|
|
|
class << self
|
|
|
|
define_method(:'c?d') do
|
2016-08-06 12:38:23 -04:00
|
|
|
"original c?d"
|
2011-03-16 18:31:57 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-03-16 18:17:47 -04:00
|
|
|
def attributes
|
2016-08-06 13:37:12 -04:00
|
|
|
{ 'a?b': "value of a?b" }
|
2011-03-16 18:17:47 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
def attribute(name)
|
|
|
|
attributes[name.to_sym]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-01-31 05:43:54 -05:00
|
|
|
class ModelWithRubyKeywordNamedAttributes
|
|
|
|
include ActiveModel::AttributeMethods
|
|
|
|
|
|
|
|
def attributes
|
2016-08-06 12:38:23 -04:00
|
|
|
{ begin: "value of begin", end: "value of end" }
|
2012-01-31 05:43:54 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
def attribute(name)
|
|
|
|
attributes[name.to_sym]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-01-15 17:54:40 -05:00
|
|
|
class ModelWithoutAttributesMethod
|
2012-01-15 06:06:50 -05:00
|
|
|
include ActiveModel::AttributeMethods
|
|
|
|
end
|
|
|
|
|
2019-08-02 00:25:13 -04:00
|
|
|
class AttributeMethodsTest < ActiveModel::TestCase
|
2016-08-06 12:38:23 -04:00
|
|
|
test "method missing works correctly even if attributes method is not defined" do
|
2012-01-15 17:54:40 -05:00
|
|
|
assert_raises(NoMethodError) { ModelWithoutAttributesMethod.new.foo }
|
2012-01-15 06:06:50 -05:00
|
|
|
end
|
|
|
|
|
2016-08-06 12:38:23 -04:00
|
|
|
test "unrelated classes should not share attribute method matchers" do
|
2020-10-02 00:47:39 -04:00
|
|
|
assert_not_equal ModelWithAttributes.public_send(:attribute_method_matchers),
|
|
|
|
ModelWithAttributes2.public_send(:attribute_method_matchers)
|
2009-10-07 10:05:54 -04:00
|
|
|
end
|
2009-10-07 10:06:54 -04:00
|
|
|
|
2016-08-06 12:38:23 -04:00
|
|
|
test "#define_attribute_method generates attribute method" do
|
2018-12-20 12:44:01 -05:00
|
|
|
ModelWithAttributes.define_attribute_method(:foo)
|
2011-02-13 12:27:33 -05:00
|
|
|
|
2018-12-20 12:44:01 -05:00
|
|
|
assert_respond_to ModelWithAttributes.new, :foo
|
|
|
|
assert_equal "value of foo", ModelWithAttributes.new.foo
|
|
|
|
ensure
|
|
|
|
ModelWithAttributes.undefine_attribute_methods
|
2011-02-13 12:27:33 -05:00
|
|
|
end
|
|
|
|
|
2016-08-06 12:38:23 -04:00
|
|
|
test "#define_attribute_method does not generate attribute method if already defined in attribute module" do
|
2011-09-13 18:46:43 -04:00
|
|
|
klass = Class.new(ModelWithAttributes)
|
2017-07-14 00:26:45 -04:00
|
|
|
klass.send(:generated_attribute_methods).module_eval do
|
2011-09-13 18:46:43 -04:00
|
|
|
def foo
|
2016-08-06 12:38:23 -04:00
|
|
|
"<3"
|
2011-09-13 18:46:43 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
klass.define_attribute_method(:foo)
|
|
|
|
|
2016-08-06 12:38:23 -04:00
|
|
|
assert_equal "<3", klass.new.foo
|
2011-09-13 18:46:43 -04:00
|
|
|
end
|
|
|
|
|
2016-08-06 12:38:23 -04:00
|
|
|
test "#define_attribute_method generates a method that is already defined on the host" do
|
2011-09-13 18:46:43 -04:00
|
|
|
klass = Class.new(ModelWithAttributes) do
|
|
|
|
def foo
|
|
|
|
super
|
|
|
|
end
|
|
|
|
end
|
|
|
|
klass.define_attribute_method(:foo)
|
|
|
|
|
2016-08-06 12:38:23 -04:00
|
|
|
assert_equal "value of foo", klass.new.foo
|
2011-09-13 18:46:43 -04:00
|
|
|
end
|
|
|
|
|
2016-08-06 12:38:23 -04:00
|
|
|
test "#define_attribute_method generates attribute method with invalid identifier characters" do
|
2018-12-20 12:44:01 -05:00
|
|
|
ModelWithWeirdNamesAttributes.define_attribute_method(:'a?b')
|
2011-03-16 18:17:47 -04:00
|
|
|
|
2018-12-20 12:44:01 -05:00
|
|
|
assert_respond_to ModelWithWeirdNamesAttributes.new, :'a?b'
|
2020-10-02 00:48:33 -04:00
|
|
|
assert_equal "value of a?b", ModelWithWeirdNamesAttributes.new.public_send("a?b")
|
2018-12-20 12:44:01 -05:00
|
|
|
ensure
|
|
|
|
ModelWithWeirdNamesAttributes.undefine_attribute_methods
|
2011-03-16 18:17:47 -04:00
|
|
|
end
|
|
|
|
|
2016-08-06 12:38:23 -04:00
|
|
|
test "#define_attribute_methods works passing multiple arguments" do
|
2018-12-20 12:44:01 -05:00
|
|
|
ModelWithAttributes.define_attribute_methods(:foo, :baz)
|
2012-05-14 12:34:35 -04:00
|
|
|
|
2018-12-20 12:44:01 -05:00
|
|
|
assert_equal "value of foo", ModelWithAttributes.new.foo
|
|
|
|
assert_equal "value of baz", ModelWithAttributes.new.baz
|
|
|
|
ensure
|
|
|
|
ModelWithAttributes.undefine_attribute_methods
|
2012-05-14 12:34:35 -04:00
|
|
|
end
|
|
|
|
|
2016-08-06 12:38:23 -04:00
|
|
|
test "#define_attribute_methods generates attribute methods" do
|
2018-12-20 12:44:01 -05:00
|
|
|
ModelWithAttributes.define_attribute_methods(:foo)
|
2009-10-07 10:06:54 -04:00
|
|
|
|
2018-12-20 12:44:01 -05:00
|
|
|
assert_respond_to ModelWithAttributes.new, :foo
|
|
|
|
assert_equal "value of foo", ModelWithAttributes.new.foo
|
|
|
|
ensure
|
|
|
|
ModelWithAttributes.undefine_attribute_methods
|
2009-10-07 10:06:54 -04:00
|
|
|
end
|
|
|
|
|
2016-08-06 12:38:23 -04:00
|
|
|
test "#alias_attribute generates attribute_aliases lookup hash" do
|
2012-06-22 10:44:01 -04:00
|
|
|
klass = Class.new(ModelWithAttributes) do
|
|
|
|
define_attribute_methods :foo
|
|
|
|
alias_attribute :bar, :foo
|
|
|
|
end
|
|
|
|
|
|
|
|
assert_equal({ "bar" => "foo" }, klass.attribute_aliases)
|
|
|
|
end
|
|
|
|
|
2016-08-06 12:38:23 -04:00
|
|
|
test "#define_attribute_methods generates attribute methods with spaces in their names" do
|
2018-12-20 12:44:01 -05:00
|
|
|
ModelWithAttributesWithSpaces.define_attribute_methods(:'foo bar')
|
2011-03-16 18:17:47 -04:00
|
|
|
|
2018-12-20 12:44:01 -05:00
|
|
|
assert_respond_to ModelWithAttributesWithSpaces.new, :'foo bar'
|
2020-10-02 00:48:33 -04:00
|
|
|
assert_equal "value of foo bar", ModelWithAttributesWithSpaces.new.public_send(:'foo bar')
|
2018-12-20 12:44:01 -05:00
|
|
|
ensure
|
|
|
|
ModelWithAttributesWithSpaces.undefine_attribute_methods
|
2011-02-03 13:46:03 -05:00
|
|
|
end
|
2011-03-16 18:17:47 -04:00
|
|
|
|
2016-08-06 12:38:23 -04:00
|
|
|
test "#alias_attribute works with attributes with spaces in their names" do
|
2018-12-20 12:44:01 -05:00
|
|
|
ModelWithAttributesWithSpaces.define_attribute_methods(:'foo bar')
|
|
|
|
ModelWithAttributesWithSpaces.alias_attribute(:'foo_bar', :'foo bar')
|
2011-03-16 18:17:47 -04:00
|
|
|
|
2018-12-20 12:44:01 -05:00
|
|
|
assert_equal "value of foo bar", ModelWithAttributesWithSpaces.new.foo_bar
|
|
|
|
ensure
|
|
|
|
ModelWithAttributesWithSpaces.undefine_attribute_methods
|
2011-02-03 13:46:03 -05:00
|
|
|
end
|
|
|
|
|
2016-08-06 12:38:23 -04:00
|
|
|
test "#alias_attribute works with attributes named as a ruby keyword" do
|
2018-12-20 12:44:01 -05:00
|
|
|
ModelWithRubyKeywordNamedAttributes.define_attribute_methods([:begin, :end])
|
|
|
|
ModelWithRubyKeywordNamedAttributes.alias_attribute(:from, :begin)
|
|
|
|
ModelWithRubyKeywordNamedAttributes.alias_attribute(:to, :end)
|
|
|
|
|
|
|
|
assert_equal "value of begin", ModelWithRubyKeywordNamedAttributes.new.from
|
|
|
|
assert_equal "value of end", ModelWithRubyKeywordNamedAttributes.new.to
|
|
|
|
ensure
|
|
|
|
ModelWithRubyKeywordNamedAttributes.undefine_attribute_methods
|
2012-01-31 05:43:54 -05:00
|
|
|
end
|
|
|
|
|
2016-08-06 12:38:23 -04:00
|
|
|
test "#undefine_attribute_methods removes attribute methods" do
|
2012-05-14 12:34:35 -04:00
|
|
|
ModelWithAttributes.define_attribute_methods(:foo)
|
2009-10-07 10:06:54 -04:00
|
|
|
ModelWithAttributes.undefine_attribute_methods
|
|
|
|
|
2018-01-24 21:14:10 -05:00
|
|
|
assert_not_respond_to ModelWithAttributes.new, :foo
|
2009-10-07 10:06:54 -04:00
|
|
|
assert_raises(NoMethodError) { ModelWithAttributes.new.foo }
|
|
|
|
end
|
2011-09-04 17:07:07 -04:00
|
|
|
|
2016-08-06 12:38:23 -04:00
|
|
|
test "accessing a suffixed attribute" do
|
2011-09-04 17:07:07 -04:00
|
|
|
m = ModelWithAttributes2.new
|
2016-08-06 12:38:23 -04:00
|
|
|
m.attributes = { "foo" => "bar" }
|
2020-01-20 10:16:02 -05:00
|
|
|
attrs = {}
|
2011-09-04 17:07:07 -04:00
|
|
|
|
2016-08-06 12:38:23 -04:00
|
|
|
assert_equal "bar", m.foo
|
2020-01-20 10:34:06 -05:00
|
|
|
assert_equal "bar", m.foo_kw(kw: 2)
|
2020-01-20 10:16:02 -05:00
|
|
|
assert_equal "bar", m.foo_test(attrs)
|
|
|
|
assert_equal "bar", attrs["foo"]
|
|
|
|
end
|
|
|
|
|
|
|
|
test "defined attribute doesn't expand positional hash argument" do
|
|
|
|
ModelWithAttributes2.define_attribute_methods(:foo)
|
|
|
|
|
|
|
|
m = ModelWithAttributes2.new
|
|
|
|
m.attributes = { "foo" => "bar" }
|
|
|
|
attrs = {}
|
|
|
|
|
|
|
|
assert_equal "bar", m.foo
|
2020-01-20 10:34:06 -05:00
|
|
|
assert_equal "bar", m.foo_kw(kw: 2)
|
2020-01-20 10:16:02 -05:00
|
|
|
assert_equal "bar", m.foo_test(attrs)
|
|
|
|
assert_equal "bar", attrs["foo"]
|
|
|
|
ensure
|
|
|
|
ModelWithAttributes2.undefine_attribute_methods
|
2011-09-04 17:07:07 -04:00
|
|
|
end
|
2011-09-09 04:08:27 -04:00
|
|
|
|
2016-08-06 12:38:23 -04:00
|
|
|
test "should not interfere with method_missing if the attr has a private/protected method" do
|
2011-09-12 17:12:12 -04:00
|
|
|
m = ModelWithAttributes2.new
|
2016-08-06 12:38:23 -04:00
|
|
|
m.attributes = { "private_method" => "<3", "protected_method" => "O_o" }
|
2011-09-12 17:12:12 -04:00
|
|
|
|
|
|
|
# dispatches to the *method*, not the attribute
|
2016-08-06 12:38:23 -04:00
|
|
|
assert_equal "<3 <3", m.send(:private_method)
|
|
|
|
assert_equal "O_o O_o", m.send(:protected_method)
|
2011-09-12 17:12:12 -04:00
|
|
|
|
|
|
|
# sees that a method is already defined, so doesn't intervene
|
|
|
|
assert_raises(NoMethodError) { m.private_method }
|
|
|
|
assert_raises(NoMethodError) { m.protected_method }
|
|
|
|
end
|
|
|
|
|
2012-03-26 14:32:21 -04:00
|
|
|
class ClassWithProtected
|
|
|
|
protected
|
2016-08-06 13:55:02 -04:00
|
|
|
def protected_method
|
|
|
|
end
|
2012-03-26 14:32:21 -04:00
|
|
|
end
|
|
|
|
|
2016-08-06 12:38:23 -04:00
|
|
|
test "should not interfere with respond_to? if the attribute has a private/protected method" do
|
2011-09-12 17:12:12 -04:00
|
|
|
m = ModelWithAttributes2.new
|
2016-08-06 12:38:23 -04:00
|
|
|
m.attributes = { "private_method" => "<3", "protected_method" => "O_o" }
|
2011-09-12 17:12:12 -04:00
|
|
|
|
2018-01-24 21:14:10 -05:00
|
|
|
assert_not_respond_to m, :private_method
|
2011-09-12 17:12:12 -04:00
|
|
|
assert m.respond_to?(:private_method, true)
|
|
|
|
|
2012-03-26 14:32:21 -04:00
|
|
|
c = ClassWithProtected.new
|
|
|
|
|
2011-09-12 17:12:12 -04:00
|
|
|
# This is messed up, but it's how Ruby works at the moment. Apparently it will be changed
|
|
|
|
# in the future.
|
2012-03-26 14:32:21 -04:00
|
|
|
assert_equal c.respond_to?(:protected_method), m.respond_to?(:protected_method)
|
2011-09-12 17:12:12 -04:00
|
|
|
assert m.respond_to?(:protected_method, true)
|
|
|
|
end
|
2011-09-12 18:58:20 -04:00
|
|
|
|
2016-08-06 12:38:23 -04:00
|
|
|
test "should use attribute_missing to dispatch a missing attribute" do
|
2011-09-12 18:58:20 -04:00
|
|
|
m = ModelWithAttributes2.new
|
2016-08-06 12:38:23 -04:00
|
|
|
m.attributes = { "foo" => "bar" }
|
2011-09-12 18:58:20 -04:00
|
|
|
|
|
|
|
def m.attribute_missing(match, *args, &block)
|
|
|
|
match
|
|
|
|
end
|
|
|
|
|
|
|
|
match = m.foo_test
|
|
|
|
|
2016-08-06 12:38:23 -04:00
|
|
|
assert_equal "foo", match.attr_name
|
|
|
|
assert_equal "attribute_test", match.target
|
2011-09-12 18:58:20 -04:00
|
|
|
end
|
2009-10-07 10:05:54 -04:00
|
|
|
end
|