Skip to content

Commit f2d8e8b

Browse files
authored
Merge pull request #195 from dry-rb/refine-accessors
Refine accessors to support invalid method names
2 parents d0d5414 + 07a7581 commit f2d8e8b

File tree

3 files changed

+44
-8
lines changed

3 files changed

+44
-8
lines changed

changelog.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
fixed:
66
- 'Fixed coercion errors for structs (issue #192 via #193)
77
(@flash-gordon)'
8+
- "Invalid method names are now allowed as struct attributes (issue #169 via #195) (@flash-gordon)"
89
changed:
910
- 'Missing attribute error now includes the name of the class (issue #170 via #191)
1011
(@phillipoertel + @cllns)'

lib/dry/struct/class_interface.rb

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -466,18 +466,27 @@ def build_type(name, type = Undefined, &)
466466
end
467467
private :build_type
468468

469+
# @api private
469470
def define_accessors(keys)
470-
keys.each do |key|
471-
next if instance_methods.include?(key)
472-
473-
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
474-
def #{key} # def email
475-
@attributes[#{key.inspect}] # @attributes[:email]
476-
end # end
477-
RUBY
471+
(keys - instance_methods).each do |key|
472+
if valid_method_name?(key)
473+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
474+
def #{key} # def email
475+
@attributes[#{key.inspect}] # @attributes[:email]
476+
end # end
477+
RUBY
478+
else
479+
define_method(key) { @attributes[key] }
480+
end
478481
end
479482
end
480483
private :define_accessors
484+
485+
# @api private
486+
def valid_method_name?(key)
487+
key.to_s.match?(/\A[a-zA-Z_]\w*\z/)
488+
end
489+
private :valid_method_name?
481490
end
482491
end
483492
end

spec/integration/attributes_from_spec.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,32 @@ class User < Dry::Struct
8484
expect(Test::User.attribute_names).to eql(%i[address])
8585
end
8686

87+
context "when attribute name is not a valid method name" do
88+
before do
89+
module Test
90+
class InvalidName < Dry::Struct
91+
attribute :"123", "string"
92+
attribute :":", "string"
93+
attribute :"with space", "string"
94+
attribute :"with-dash", "string"
95+
end
96+
end
97+
end
98+
99+
it "adds an accessor" do
100+
odd_struct = Test::InvalidName.new(
101+
"123": "John",
102+
":": "Jane",
103+
"with space": "Doe",
104+
"with-dash": "Smith"
105+
)
106+
expect(odd_struct.public_send(:"123")).to eql("John")
107+
expect(odd_struct.public_send(:":")).to eql("Jane")
108+
expect(odd_struct.public_send("with space")).to eql("Doe")
109+
expect(odd_struct.public_send("with-dash")).to eql("Smith")
110+
end
111+
end
112+
87113
context "inheritance" do
88114
before do
89115
class Test::Person < Dry::Struct

0 commit comments

Comments
 (0)