diff --git a/lib/hammer_cli/main.rb b/lib/hammer_cli/main.rb index 49742f00..74ebef82 100644 --- a/lib/hammer_cli/main.rb +++ b/lib/hammer_cli/main.rb @@ -39,6 +39,9 @@ class MainCommand < AbstractCommand option ["--interactive"], "INTERACTIVE", _("Explicitly turn interactive mode on/off"), :format => HammerCLI::Options::Normalizers::Bool.new, :context_target => :interactive + option ["--only"], "FIELDS", _("Show selected columns or fields only"), + :format => HammerCLI::Options::Normalizers::List.new, + :context_target => :only option ["--no-headers"], :flag, _("Hide headers from output") option ["--csv"], :flag, _("Output as CSV (same as --output=csv)") option ["--output"], "ADAPTER", _("Set output format. One of [%s]") % diff --git a/lib/hammer_cli/output/adapter/tree_structure.rb b/lib/hammer_cli/output/adapter/tree_structure.rb index 3caf672b..6207d2ec 100644 --- a/lib/hammer_cli/output/adapter/tree_structure.rb +++ b/lib/hammer_cli/output/adapter/tree_structure.rb @@ -7,9 +7,10 @@ def initialize(context={}, formatters={}) end def prepare_collection(fields, collection) - collection.map do |element| + prepared = collection.map do |element| render_fields(fields, element) end + reduce_collection(prepared) end protected @@ -75,5 +76,27 @@ def numbered_data(data) end end + private + + def reduce_collection(collection) + return collection unless @context.key?(:only) + reduced = [] + collection.each do |record| + reduced << reduce_record(record, @context[:only]) + end + reduced + end + + def reduce_record(record, keys) + reduced = {} + record.each do |key, value| + if keys.include?(key) + reduced[key] = value + elsif value.is_a? Hash + reduced.merge!(reduce_record(value, keys)) + end + end + reduced + end end end diff --git a/lib/hammer_cli/output/output.rb b/lib/hammer_cli/output/output.rb index 62ecc9df..649df52e 100644 --- a/lib/hammer_cli/output/output.rb +++ b/lib/hammer_cli/output/output.rb @@ -17,6 +17,7 @@ def print_error(msg, details=nil, msg_params={}) end def print_record(definition, record) + adjust_definition(definition) adapter.print_record(definition.fields, record) end @@ -24,6 +25,7 @@ def print_collection(definition, collection) unless collection.class <= HammerCLI::Output::RecordCollection collection = HammerCLI::Output::RecordCollection.new([collection].flatten(1)) end + adjust_definition(definition) adapter.print_collection(definition.fields, collection) end @@ -69,5 +71,11 @@ def init_adapter(adapter_name) @adapter ||= self.class.adapters[adapter_name].new(context, self.class.formatters) end + def adjust_definition(definition) + return unless @context.key?(:only) + return if adapter.class <= HammerCLI::Output::Adapter::TreeStructure + labels = @context[:only].map(&:downcase) + definition.select_fields!(deep_select: true, labels: labels) + end end end diff --git a/test/unit/output/adapter/base_test.rb b/test/unit/output/adapter/base_test.rb index 86d949b6..31ac3767 100644 --- a/test/unit/output/adapter/base_test.rb +++ b/test/unit/output/adapter/base_test.rb @@ -220,6 +220,23 @@ end + context '--only' do + let(:selected_fields) { [name.label] } + let(:context) { { :only => selected_fields, :adapter => :base } } + let(:output) { HammerCLI::Output::Output.new(context) } + + it 'should print selected fields only' do + fields = [name, surname, city] + output_definition = HammerCLI::Output::Definition.new + output_definition.fields = fields + expected_output = [ + 'Name: John', + "\n" + ].join("\n") + + proc { output.print_collection(output_definition, data) }.must_output(expected_output) + end + end end end diff --git a/test/unit/output/adapter/csv_test.rb b/test/unit/output/adapter/csv_test.rb index b693db4d..8e5d1709 100644 --- a/test/unit/output/adapter/csv_test.rb +++ b/test/unit/output/adapter/csv_test.rb @@ -227,6 +227,20 @@ def format(data, field_params={}) end + context '--only' do + let(:selected_fields) { [field_name.label] } + let(:context) { {:only => selected_fields, :adapter => :csv } } + let(:output) { HammerCLI::Output::Output.new(context) } + + it 'should print selected fields only' do + fields = [field_name, field_started_at] + output_definition = HammerCLI::Output::Definition.new + output_definition.fields = fields + expected_output = "Name\nJohn Doe\n" + + proc { output.print_collection(output_definition, data) }.must_output(expected_output) + end + end end context "print message" do diff --git a/test/unit/output/adapter/json_test.rb b/test/unit/output/adapter/json_test.rb index ff24b113..8db3ccf3 100644 --- a/test/unit/output/adapter/json_test.rb +++ b/test/unit/output/adapter/json_test.rb @@ -268,6 +268,18 @@ end + context '--only' do + let(:selected_fields) { [name.label] } + let(:context) { {:only => selected_fields } } + + it 'should print selected fields only' do + fields = [name, surname, city] + hash = [{ 'Name' => 'John' }] + expected_output = JSON.pretty_generate(hash) + "\n" + + proc { adapter.print_collection(fields, data) }.must_output(expected_output) + end + end end end diff --git a/test/unit/output/adapter/table_test.rb b/test/unit/output/adapter/table_test.rb index 94ac8108..d19f3815 100644 --- a/test/unit/output/adapter/table_test.rb +++ b/test/unit/output/adapter/table_test.rb @@ -380,6 +380,27 @@ def format(data, field_params={}) end + context '--only' do + let(:selected_fields) { [field_firstname.label] } + let(:context) { {:only => selected_fields, :adapter => :table } } + let(:output) { HammerCLI::Output::Output.new(context) } + + it 'should print selected fields only' do + fields = [field_firstname, field_lastname, field_long] + output_definition = HammerCLI::Output::Definition.new + output_definition.fields = fields + expected_output = [ + "---------", + "FIRSTNAME", + "---------", + "John ", + "---------", + "" + ].join("\n") + + proc { output.print_collection(output_definition, data) }.must_output(expected_output) + end + end end end diff --git a/test/unit/output/adapter/yaml_test.rb b/test/unit/output/adapter/yaml_test.rb index 50c413cd..adf43ee1 100644 --- a/test/unit/output/adapter/yaml_test.rb +++ b/test/unit/output/adapter/yaml_test.rb @@ -265,6 +265,18 @@ end + context '--only' do + let(:selected_fields) { [name.label] } + let(:context) { { :only => selected_fields } } + + it 'should print selected fields only' do + fields = [name, surname, city] + hash = [{ 'Name' => 'John' }] + expected_output = YAML.dump(hash) + + proc { adapter.print_collection(fields, data) }.must_output(expected_output) + end + end end end