diff --git a/app/services/foreman/renderer/scope/report.rb b/app/services/foreman/renderer/scope/report.rb index 84c478de66a..4de1b19aefa 100644 --- a/app/services/foreman/renderer/scope/report.rb +++ b/app/services/foreman/renderer/scope/report.rb @@ -59,17 +59,20 @@ def report_headers(*headers) The only argument it accepts is a record definition. This is typically called in some **each** loop. Calling this at least once is important so we know what columns are to be rendered in this report. Calling this macro adds a record to the rendering queue." - required :row_data, Hash, desc: 'Data in form of hash, keys are column names, values are values for this record' + optional :row_data, Hash, desc: 'Data in form of hash, keys are column names, values are values for this record', default: {} + kwlist :row_data_kw, desc: 'Data in form of key: value list, keys are column names, values are values for this record' returns Array, desc: 'Currently registered report data' example "report_row(:name => 'host1.example.com', :ip => '192.168.0.2')" example "<%- load_hosts.each_record do |host|\n report_row(:name => host.name, :ip => host.ip)\nend -%>" end - def report_row(row_data) - new_headers = row_data.keys + # accept either a hash or kwargs for compatibility with Ruby 2.7 & 3 + def report_row(row_data = {}, **row_data_kws) + data = row_data_kws.transform_keys(&:to_s).merge(row_data.transform_keys(&:to_s)) + new_headers = data.keys if @report_headers.size < new_headers.size - @report_headers |= new_headers.map(&:to_s) + @report_headers |= new_headers end - @report_data << row_data.values + @report_data << data.values end def apply_order!(order) diff --git a/test/unit/foreman/renderer/scope/report_test.rb b/test/unit/foreman/renderer/scope/report_test.rb index a8284fac8ff..46cfe6448fd 100644 --- a/test/unit/foreman/renderer/scope/report_test.rb +++ b/test/unit/foreman/renderer/scope/report_test.rb @@ -58,6 +58,29 @@ class ReportScopeTest < ActiveSupport::TestCase assert_equal expected_yaml, @scope.report_render(format: :yaml) end + test 'report_row handles symbol keys with safemode merge' do + renderer = Foreman::Renderer::SafeModeRenderer + base_opts = { 'Fruit1' => 'Apple', 'Fruit2' => 'Banana' } + + content = "<%= report_row({ + :Name => 'Orange', + :Global => 'Pomegranate' + }.merge(@base_opts)) %>" + source = OpenStruct.new( + name: 'Test', + content: content + ) + @scope = Foreman::Renderer::Scope::Report.new( + source: source, + variables: { base_opts: base_opts } + ) + result = "" + assert_nothing_raised do + result = renderer.render(source, @scope) + end + assert_equal result, "[[\"Orange\", \"Pomegranate\", \"Apple\", \"Banana\"]]" + end + test 'render types' do @scope.report_row( 'List': ['Val1', 1, true],