Skip to content

Commit 2f9b820

Browse files
committed
Merge branch 'main' into keyword-field-options
2 parents a7d469d + 91bf963 commit 2f9b820

File tree

6 files changed

+93
-12
lines changed

6 files changed

+93
-12
lines changed

.github/workflows/auto-assign-author.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ jobs:
66
assign-author:
77
runs-on: ubuntu-latest
88
steps:
9-
- uses: toshimaru/auto-author-assign@16f0022cf3d7970c106d8d1105f75a1165edb516 # v2.1.1
9+
- uses: toshimaru/auto-author-assign@4d585cc37690897bd9015942ed6e766aa7cdb97f # v3.0.1
1010
with:
1111
repo-token: "${{ secrets.GITHUB_TOKEN }}"

.github/workflows/codeql.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ jobs:
2222
language: ['ruby']
2323
steps:
2424
- name: Checkout repository
25-
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4
25+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v4
2626
- name: Initialize CodeQL
27-
uses: github/codeql-action/init@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v3
27+
uses: github/codeql-action/init@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v3
2828
with:
2929
languages: ${{ matrix.language }}
3030
- name: Autobuild
31-
uses: github/codeql-action/autobuild@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v3
31+
uses: github/codeql-action/autobuild@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v3
3232
- name: Perform CodeQL Analysis
33-
uses: github/codeql-action/analyze@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v3
33+
uses: github/codeql-action/analyze@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v3
3434
with:
3535
category: "/language:${{matrix.language}}"

.github/workflows/release.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,20 @@ jobs:
1212
outputs:
1313
changed: ${{ steps.check.outputs.any_changed }}
1414
steps:
15-
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4
15+
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v4
1616
- name: Check if version has been updated
1717
id: check
18-
uses: tj-actions/changed-files@70069877f29101175ed2b055d210fe8b1d54d7d7 # v44
18+
uses: tj-actions/changed-files@3c4bc6fa0ca4718d438e0a4bd3ea81fbb0e6e2be # v44
1919
with:
2020
files: lib/blueprinter/version.rb
2121
release:
2222
runs-on: ubuntu-latest
2323
needs: version-check
2424
if: ${{ github.event_name == 'workflow_dispatch' || needs.version-check.outputs.changed == 'true' }}
2525
steps:
26-
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4
26+
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v4
2727
- name: Set up Ruby
28-
uses: ruby/setup-ruby@d697be2f83c6234b20877c3b5eac7a7f342f0d0c # v1
28+
uses: ruby/setup-ruby@675dd7ba1b06c8786a1480d89c384f5620a42647 # v1
2929
with:
3030
ruby-version: 3.2
3131
bundler-cache: true

.github/workflows/test.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ jobs:
1414
ruby: ['3.1', '3.2', '3.3']
1515
runs-on: ${{ matrix.os }}
1616
steps:
17-
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4
17+
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v4
1818
- name: Set up Ruby ${{ matrix.ruby }}
19-
uses: ruby/setup-ruby@d697be2f83c6234b20877c3b5eac7a7f342f0d0c # v1
19+
uses: ruby/setup-ruby@675dd7ba1b06c8786a1480d89c384f5620a42647 # v1
2020
with:
2121
ruby-version: ${{ matrix.ruby }}
2222
bundler-cache: true

lib/blueprinter/extractors/block_extractor.rb

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,31 @@ module Blueprinter
66
# @api private
77
class BlockExtractor < Extractor
88
def extract(_field_name, object, local_options, options = {})
9-
options[:block].call(object, **local_options)
9+
block = options[:block]
10+
11+
# Symbol#to_proc creates procs with signature [[:req], [:rest]]
12+
# These procs forward ALL arguments to the method, which causes
13+
# issues when we call block.call(object, local_options) because
14+
# it becomes object.method_name(local_options), and most methods
15+
# don't accept extra arguments.
16+
#
17+
# For Symbol#to_proc, we only pass the object.
18+
# For regular blocks, we pass both object and local_options.
19+
if symbol_to_proc?(block)
20+
block.call(object)
21+
else
22+
block.call(object, **local_options)
23+
end
24+
end
25+
26+
private
27+
28+
def symbol_to_proc?(block)
29+
# Symbol#to_proc has a characteristic signature:
30+
# - Parameters: [[:req], [:rest]] (one required + rest args)
31+
# - This is different from regular blocks which typically have
32+
# optional parameters like [[:opt, :obj], [:opt, :options]]
33+
block.parameters == [[:req], [:rest]]
1034
end
1135
end
1236
end

spec/integrations/base_spec.rb

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,63 @@
5555
end
5656
end
5757

58+
context 'when using Symbol#to_proc syntax' do
59+
let(:obj) { object_with_attributes }
60+
61+
context 'with field using &:method_name' do
62+
let(:blueprint) do
63+
Class.new(Blueprinter::Base) do
64+
identifier :id
65+
field :name, &:first_name
66+
field :job_position, &:position
67+
end
68+
end
69+
70+
it 'renders the field by calling the method on the object' do
71+
result = JSON.parse(blueprint.render(obj))
72+
expect(result['id']).to eq(1)
73+
expect(result['name']).to eq('Meg')
74+
expect(result['job_position']).to eq('Manager')
75+
end
76+
end
77+
78+
context 'with identifier using &:method_name' do
79+
let(:blueprint) do
80+
Class.new(Blueprinter::Base) do
81+
identifier :user_id, &:id
82+
field :first_name
83+
end
84+
end
85+
86+
it 'renders the identifier using Symbol#to_proc' do
87+
expect(blueprint.render(obj)).to eq('{"user_id":1,"first_name":"Meg"}')
88+
end
89+
end
90+
91+
context 'when mixing Symbol#to_proc and regular blocks' do
92+
let(:blueprint) do
93+
Class.new(Blueprinter::Base) do
94+
identifier :id
95+
field :name, &:first_name
96+
field :full_name do |obj|
97+
"#{obj.first_name} #{obj.last_name}"
98+
end
99+
field :info do |obj, options|
100+
"#{obj.position} (options: #{options.inspect})"
101+
end
102+
end
103+
end
104+
105+
it 'handles both block types correctly' do
106+
result = JSON.parse(blueprint.render(obj))
107+
expect(result['id']).to eq(1)
108+
expect(result['name']).to eq('Meg')
109+
expect(result['full_name']).to eq('Meg Ryan')
110+
expect(result['info']).to include('Manager')
111+
end
112+
end
113+
end
114+
58115
context 'Outside Rails project' do
59116
context 'Given passed object has dot notation accessible attributes' do
60117
let(:obj) { object_with_attributes }

0 commit comments

Comments
 (0)