Skip to content

Commit

Permalink
Extend builder DSL to take implicit arrays and hashes
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisandreae committed Feb 15, 2024
1 parent 963f33a commit 62cbab2
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 12 deletions.
25 changes: 16 additions & 9 deletions lib/keyword_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,22 +66,29 @@ def initialize(initial_attrs)
@attrs = initial_attrs.dup
end

def _set_attribute(attr, *args, &block)
def _set_attribute(attr, *args, **kwargs, &block)
if attrs.has_key?(attr)
raise BuilderError.new("Invalid builder state: #{attr} already provided")
end

value =
if block_given?
raise ArgumentError.new('Cannot provide both immediate and block value') unless args.blank?
if kwargs.empty?
value = args.dup

block
elsif args.size == 1
args[0]
else
raise ArgumentError.new('Wrong number of arguments: expected 1 or block')
value << block if block_given?

if value.empty?
raise ArgumentError.new('Wrong number of arguments: expected at least one argument or block')
end

value = value[0] if value.size == 1
else
unless args.empty? && block.nil?
raise ArgumentError.new('Invalid arguments: cannot provide both keyword and positional arguments')
end

value = kwargs.dup
end

attrs[attr] = value
end

Expand Down
38 changes: 35 additions & 3 deletions spec/unit/keyword_builder_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,32 @@ def initialize(a:, b:, c:)
expect(result).to have_attributes(a: 1, b: 2, c: 3)
end

it 'constructs an array when builder is given more than one argument' do
result = builder.build!(a: 1, b: 2) do
c(1, 2, 3)
end

expect(result).to have_attributes(a: 1, b: 2, c: [1, 2, 3])
end

it 'constructs an array when builder is given arguments and a block' do
p = proc { 1 }

result = builder.build!(a: 1, b: 2) do
c(3, &p)
end

expect(result).to have_attributes(a: 1, b: 2, c: [3, p])
end

it 'constructs an hash when builder is given keyword arguments' do
result = builder.build!(a: 1, b: 2) do
c(x: 3, y: 4)
end

expect(result).to have_attributes(a: 1, b: 2, c: { x: 3, y: 4 })
end

it 'rejects arguments colliding with builder' do
expect {
builder.build!(a: 1, b: 2, c: 3) { a 1 }
Expand All @@ -55,10 +81,16 @@ def initialize(a:, b:, c:)
}.to raise_error(ArgumentError, /Wrong number of arguments/)
end

it 'requires only one argument' do
it 'rejects mixed keyword and positional arguments' do
expect {
builder.build!(a: 1, b: 2) { c(1, 2, 3) }
}.to raise_error(ArgumentError, /Wrong number of arguments/)
builder.build!(a: 1, b: 2) { c(3, x: 4) }
}.to raise_error(ArgumentError, /Invalid arguments/)
end

it 'rejects mixed keyword and block arguments' do
expect {
builder.build!(a: 1, b: 2) { c(x: 3) { 4 } }
}.to raise_error(ArgumentError, /Invalid arguments/)
end

it 'rejects unknown arguments' do
Expand Down

0 comments on commit 62cbab2

Please sign in to comment.