Class: Chef::Knife::Core::GenericPresenter

Inherits:
Object
  • Object
show all
Defined in:
lib/chef/knife/core/generic_presenter.rb

Overview

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

Direct Known Subclasses

NodePresenter, StatusPresenter

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(ui, config) ⇒ GenericPresenter

Instantiates a new GenericPresenter. This is generally handled by the Chef::Knife::UI object, though you need to match the signature of this method if you intend to use your own presenter instead.



60
61
62
# File 'lib/chef/knife/core/generic_presenter.rb', line 60

def initialize(ui, config)
  @ui, @config = ui, config
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



55
56
57
# File 'lib/chef/knife/core/generic_presenter.rb', line 55

def config
  @config
end

#uiObject (readonly)

Returns the value of attribute ui.



54
55
56
# File 'lib/chef/knife/core/generic_presenter.rb', line 54

def ui
  @ui
end

Instance Method Details

#attribute_field_separatorObject

GenericPresenter is used in contexts where MultiAttributeReturnOption is not, so we need to set the default value here rather than as part of the CLI option.



186
187
188
# File 'lib/chef/knife/core/generic_presenter.rb', line 186

def attribute_field_separator
  config[:field_separator] || "."
end

#extract_nested_value(data, nested_value_spec) ⇒ Object



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/chef/knife/core/generic_presenter.rb', line 190

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

#format(data) ⇒ Object

Returns a String representation of data that is suitable for output to a terminal or perhaps for data interchange with another program. The representation of the data depends on the value of the ‘config` setting.



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/chef/knife/core/generic_presenter.rb', line 81

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

#format_cookbook_list_for_display(item) ⇒ Object



208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/chef/knife/core/generic_presenter.rb', line 208

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

#format_data_subset_for_display(data) ⇒ Object



158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/chef/knife/core/generic_presenter.rb', line 158

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

#format_for_display(data) ⇒ Object



146
147
148
149
150
151
152
153
154
155
156
# File 'lib/chef/knife/core/generic_presenter.rb', line 146

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

#format_list_for_display(list) ⇒ Object



142
143
144
# File 'lib/chef/knife/core/generic_presenter.rb', line 142

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

#formatting_subset_of_data?Boolean

Returns:

  • (Boolean)


179
180
181
# File 'lib/chef/knife/core/generic_presenter.rb', line 179

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

#interchange?Boolean

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

Returns:

  • (Boolean)


68
69
70
71
72
73
74
75
# File 'lib/chef/knife/core/generic_presenter.rb', line 68

def interchange?
  case parse_format_option
  when :json, :yaml
    true
  else
    false
  end
end

#name_or_id_for(data) ⇒ Object



175
176
177
# File 'lib/chef/knife/core/generic_presenter.rb', line 175

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

#parse_format_optionObject

Converts the user-supplied value of ‘config` to a Symbol representing the desired output format.

Returns

returns one of :summary, :text, :json, :yaml, or :pp

Raises

Raises an ArgumentError if the desired output format could not be determined from the value of ‘config`



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/chef/knife/core/generic_presenter.rb', line 113

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

#summarize(data) ⇒ Object

Summarize the data. Defaults to text format output, which may not be very summary-like



132
133
134
# File 'lib/chef/knife/core/generic_presenter.rb', line 132

def summarize(data)
  text_format(data)
end

#text_format(data) ⇒ Object

Converts the data to a String in the text format. Uses Chef::Knife::Core::TextFormatter



138
139
140
# File 'lib/chef/knife/core/generic_presenter.rb', line 138

def text_format(data)
  TextFormatter.new(data, ui).formatted_data
end