diff --git a/lib/props_template.rb b/lib/props_template.rb index 2cb0920..3ef6dd8 100644 --- a/lib/props_template.rb +++ b/lib/props_template.rb @@ -59,7 +59,11 @@ def set!(key, options = {}, &block) @builder = prev_builder @fragment_path = fragment_path - if found_block + # An inline options object, e.g. `json.foo(with.partial("foo"))`, has + # no block; its content comes from the options instead. + found_inline_options = found_options.is_a?(Props::Options) + + if found_block || found_inline_options @builder.item_context = found_item set!(key, found_options, &found_block) end @@ -72,8 +76,11 @@ def partial!(**options) @context.render options end + # Relative to the fragment the dig ended in, so the client can graft into + # it; the full path when no fragment was crossed. def found_path! - @found_path[@fragment_path.size..].join(".") + fragment_path = @fragment_path || [] + @found_path[fragment_path.size..].join(".") end def fragment_context! diff --git a/spec/extensions/prop_template_search_spec.rb b/spec/extensions/prop_template_search_spec.rb index b96f8b4..9f3e536 100644 --- a/spec/extensions/prop_template_search_spec.rb +++ b/spec/extensions/prop_template_search_spec.rb @@ -239,6 +239,23 @@ }) end + it "finds a node that is an inline options object" do + json = render(<<~PROPS) + json.data(dig: ['data', 'comment']) do + json.comment(Props::Options.new.partial('comment')) + end + PROPS + + expect(json).to eql_json({ + data: { + title: "some title", + details: { + body: "hello world" + } + } + }) + end + it "finds a subtree" do json = render(<<-PROPS) json.outer(dig: ['outer','inner', 'deep']) do @@ -427,6 +444,65 @@ }) end + context "grafting path without a fragment" do + it "is the full path when digging through plain nodes" do + json = render(<<~PROPS) + json.data(dig: ['data', 'comment', 'details']) do + json.comment do + json.details do + json.body 'hello world' + end + end + end + json.fragmentContext json.fragment_context! + json.path json.found_path! + PROPS + + expect(json).to eql_json({ + data: { + body: "hello world" + }, + fragmentContext: nil, + path: "data.comment.details" + }) + end + + it "is the full path when digging through a partial without a fragment" do + json = render(<<~PROPS) + json.data(dig: ['data', 'comment', 'details']) do + json.comment(partial: 'comment') do + end + end + json.fragmentContext json.fragment_context! + json.path json.found_path! + PROPS + + expect(json).to eql_json({ + data: { + body: "hello world" + }, + fragmentContext: nil, + path: "data.comment.details" + }) + end + + it "is empty without digging" do + json = render(<<~PROPS) + json.data do + json.body 'hello world' + end + json.path json.found_path! + PROPS + + expect(json).to eql_json({ + data: { + body: "hello world" + }, + path: "" + }) + end + end + context "when searching through a partial" do it "returns the correct node in an object" do json = render(<<~PROPS)