Skip to content

Commit 4837c6c

Browse files
committed
Add default_keyword_init option
1 parent 97e84df commit 4837c6c

File tree

2 files changed

+47
-8
lines changed

2 files changed

+47
-8
lines changed

lib/typed_struct.rb

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,21 @@ class TypedStruct < Struct
1818
alias_method :__class__, :class
1919

2020
class << self
21+
def default_keyword_init
22+
@@default_keyword_init
23+
end
24+
25+
def default_keyword_init=(default)
26+
@@default_keyword_init = default
27+
end
28+
2129
def new(opts = Options.new, **properties)
22-
if const_defined?("RSpec") && RUBY_VERSION < "3.2" && opts[:keyword_init].nil?
23-
opts[:keyword_init] = false
30+
if opts[:keyword_init].nil?
31+
opts[:keyword_init] = if RUBY_VERSION < "3.2"
32+
default_keyword_init || false
33+
else
34+
default_keyword_init
35+
end
2436
end
2537

2638
properties.each_key do |prop|

spec/typed_struct_spec.rb

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# frozen_string_literal: true
22

33
RSpec.describe TypedStruct do
4+
before { TypedStruct.default_keyword_init = nil }
5+
46
it "helps avoid primitive obsession" do
57
Price = TypedStruct.new(price: Rational) do
68
%i[- + / *].each do |op|
@@ -28,6 +30,31 @@
2830
expect { y.int = "abc" }.to raise_error TypeError
2931
end
3032

33+
it "has default_keyword_init option" do
34+
attrs = RUBY_VERSION < "3.2" ? {int: {int: 5}} : {int: 5}
35+
36+
TypedStruct.default_keyword_init = nil
37+
expect(TypedStruct.default_keyword_init).to be nil
38+
x = Struct.new(:int)
39+
y = TypedStruct.new(int: Rbs("untyped"))
40+
expect(x.new(int: 5)).to have_attributes attrs
41+
expect(y.new(int: 5)).to have_attributes attrs
42+
43+
TypedStruct.default_keyword_init = true
44+
expect(TypedStruct.default_keyword_init).to be true
45+
x = Struct.new(:int, keyword_init: true)
46+
y = TypedStruct.new(int: Rbs("untyped"))
47+
expect(x.new(int: 5)).to have_attributes int: 5
48+
expect(y.new(int: 5)).to have_attributes int: 5
49+
50+
TypedStruct.default_keyword_init = false
51+
expect(TypedStruct.default_keyword_init).to be false
52+
x = Struct.new(:int, keyword_init: false)
53+
y = TypedStruct.new(int: Rbs("untyped"))
54+
expect(x.new(int: 5)).to have_attributes int: {int: 5}
55+
expect(y.new(int: 5)).to have_attributes int: {int: 5}
56+
end
57+
3158
it "has an options attribute" do
3259
x = TypedStruct.new(int: Integer, str: String)
3360
expect(x.instance_variables).to contain_exactly :@options
@@ -45,13 +72,11 @@
4572
y = TypedStruct.new(int: Rbs("untyped"))
4673
attrs = RUBY_VERSION < "3.2" ? {int: {int: 5}} : {int: 5}
4774
expect(x.new(5)).to have_attributes int: 5
48-
expect(x.new(int: 5)).to have_attributes attrs
4975
expect(y.new(5)).to have_attributes int: 5
76+
expect(x.new(int: 5)).to have_attributes attrs
5077
expect(y.new(int: 5)).to have_attributes attrs
5178
x = Struct.new(:int, keyword_init: true)
5279
y = TypedStruct.new({ keyword_init: true }, int: Rbs("untyped"))
53-
expect { x.new(5) }.to raise_error ArgumentError, "wrong number of arguments (given 1, expected 0)"
54-
expect { y.new(5) }.to raise_error ArgumentError, "wrong number of arguments (given 1, expected 0)"
5580
expect(x.new(int: 5)).to have_attributes int: 5
5681
expect(y.new(int: 5)).to have_attributes int: 5
5782
end
@@ -71,13 +96,15 @@
7196

7297
it "has identical error messages for presence checks" do
7398
x = Struct.new(:int, keyword_init: true)
74-
expect { x.new(str: 5, abc: "xyz") }.to raise_error ArgumentError, "unknown keywords: str, abc"
7599
y = TypedStruct.new({ keyword_init: true }, int: Integer)
100+
expect { x.new(5) }.to raise_error ArgumentError, "wrong number of arguments (given 1, expected 0)"
101+
expect { y.new(5) }.to raise_error ArgumentError, "wrong number of arguments (given 1, expected 0)"
102+
expect { x.new(str: 5, abc: "xyz") }.to raise_error ArgumentError, "unknown keywords: str, abc"
76103
expect { y.new(str: 5, abc: "xyz") }.to raise_error ArgumentError, "unknown keywords: str, abc"
77104
a = x.new(int: 5)
105+
b = y.new(int: 5)
78106
expect { a.str = 5 }.to raise_error NoMethodError, "undefined method `str=' for #<struct int=5>"
79107
expect { a[:str] = 5 }.to raise_error NameError, "no member 'str' in struct"
80-
b = y.new(int: 5)
81108
expect { b.str = 5 }.to raise_error NoMethodError, "undefined method `str=' for #<struct int=5>"
82109
expect { b[:str] = 5 }.to raise_error NameError, "no member 'str' in struct"
83110
x = Struct.new(:int)
@@ -89,7 +116,7 @@
89116
it "supports the same methods" do
90117
a = Struct.new(:str, :int)
91118
b = TypedStruct.new(str: String, int: Integer)
92-
expect(a.public_methods).to contain_exactly *b.public_methods
119+
expect(a.public_methods).to contain_exactly *b.public_methods.grep_v(:default_keyword_init).grep_v(:default_keyword_init=)
93120
expect(a.public_instance_methods).to contain_exactly *b.public_instance_methods.grep_v(:__class__)
94121
expect(a.public_instance_methods(false)).to contain_exactly *b.new("abc", 5).public_methods(false).grep_v(:[]=)
95122
end

0 commit comments

Comments
 (0)