class Chef::Knife::Core::GenericPresenter

most kinds of objects that knife needs to display.
This is not an abstract base class, and it is suitable for displaying
The base presenter class for displaying structured data in knife commands.

def attribute_field_separator

of the CLI option.
is not, so we need to set the default value here rather than as part
GenericPresenter is used in contexts where MultiAttributeReturnOption
def attribute_field_separator
  config[:field_separator] || "."
end

def extract_nested_value(data, nested_value_spec)

def extract_nested_value(data, nested_value_spec)
  nested_value_spec.split(attribute_field_separator).each do |attr|
    data =
      if data.is_a?(Array)
        data[attr.to_i]
      elsif data.respond_to?(:[], false) && data.respond_to?(:key?) && data.key?(attr)
        data[attr]
      elsif data.respond_to?(attr.to_sym, false)
        # handles -a chef_environment and other things that hang of the node and aren't really attributes

        data.public_send(attr.to_sym)
      else
        nil
      end
  end
  # necessary (?) for coercing objects (the run_list object?) to hashes

  ( !data.is_a?(Array) && data.respond_to?(:to_hash) ) ? data.to_hash : data
end

def format(data)

`config[:format]` setting.
The representation of the +data+ depends on the value of the
to a terminal or perhaps for data interchange with another program.
Returns a String representation of +data+ that is suitable for output
def format(data)
  case parse_format_option
  when :summary
    summarize(data)
  when :text
    text_format(data)
  when :json
    Chef::JSONCompat.to_json_pretty(data)
  when :yaml
    require "yaml" unless defined?(YAML)
    YAML.dump(data)
  when :pp
    require "stringio" unless defined?(StringIO)
    # If you were looking for some attribute and there is only one match

    # just dump the attribute value

    if config[:attribute] && data.length == 1
      data.values[0]
    else
      out = StringIO.new
      PP.pp(data, out)
      out.string
    end
  end
end

def format_cookbook_list_for_display(item)

def format_cookbook_list_for_display(item)
  versions_by_cookbook = item.inject({}) do |collected, ( cookbook, versions )|
    if config[:with_uri]
      collected[cookbook] = {}
      versions["versions"].each do |ver|
        collected[cookbook][ver["version"]] = ver["url"]
      end
    else
      collected[cookbook] = versions["versions"].map { |v| v["version"] }
    end
    collected.sort.to_h
  end
  if config[:with_uri]
    versions_by_cookbook
  else
    case parse_format_option
      when :summary
        cookbooks = {}
        versions_by_cookbook.map do |cookbook, versions|
          cookbooks[cookbook] = versions.join(" ")
        end
        cookbooks
      else
        versions_by_cookbook
    end
  end
end

def format_data_subset_for_display(data)

def format_data_subset_for_display(data)
  subset = if config[:attribute]
             result = {}
             Array(config[:attribute]).each do |nested_value_spec|
               nested_value = extract_nested_value(data, nested_value_spec)
               result[nested_value_spec] = nested_value
             end
             result
           elsif config[:run_list]
             run_list = data.run_list.run_list
             { "run_list" => run_list }
           else
             raise ArgumentError, "format_data_subset_for_display requires attribute, run_list, or id_only config option to be set"
           end
  { name_or_id_for(data) => subset }
end

def format_for_display(data)

def format_for_display(data)
  if formatting_subset_of_data?
    format_data_subset_for_display(data)
  elsif config[:id_only]
    name_or_id_for(data)
  elsif config[:environment] && data.respond_to?(:chef_environment)
    { "chef_environment" => data.chef_environment }
  else
    data
  end
end

def format_list_for_display(list)

def format_list_for_display(list)
  config[:with_uri] ? list : list.keys.sort
end

def formatting_subset_of_data?

def formatting_subset_of_data?
  config[:attribute] || config[:run_list]
end

def initialize(ui, config)

method if you intend to use your own presenter instead.
Chef::Knife::UI object, though you need to match the signature of this
Instantiates a new GenericPresenter. This is generally handled by the
def initialize(ui, config)
  @ui, @config = ui, config
end

def interchange?

to produce invalid JSON output.
otherwise. Knife search uses this to adjust its data output so as not
Returns true if the selected output format is json or yaml, false
Is the selected output format a data interchange format?
def interchange?
  case parse_format_option
  when :json, :yaml
    true
  else
    false
  end
end

def name_or_id_for(data)

def name_or_id_for(data)
  data.respond_to?(:name) ? data.name : data["id"]
end

def parse_format_option

determined from the value of `config[:format]`
Raises an ArgumentError if the desired output format could not be
===Raises
returns one of :summary, :text, :json, :yaml, or :pp
===Returns
representing the desired output format.
Converts the user-supplied value of `config[:format]` to a Symbol
def parse_format_option
  case config[:format]
  when "summary", /^s/, nil
    :summary
  when "text", /^t/
    :text
  when "json", /^j/
    :json
  when "yaml", /^y/
    :yaml
  when "pp", /^p/
    :pp
  else
    raise ArgumentError, "Unknown output format #{config[:format]}"
  end
end

def summarize(data)

which may not be very summary-like
Summarize the data. Defaults to text format output,
def summarize(data)
  text_format(data)
end

def text_format(data)

Chef::Knife::Core::TextFormatter
Converts the +data+ to a String in the text format. Uses
def text_format(data)
  TextFormatter.new(data, ui).formatted_data
end