hammer_cli 0.15.1 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/doc/commands_modification.md +82 -0
  3. data/doc/creating_commands.md +78 -38
  4. data/doc/developer_docs.md +2 -0
  5. data/doc/help_modification.md +119 -0
  6. data/doc/i18n.md +2 -2
  7. data/doc/installation_rpm.md +3 -3
  8. data/doc/release_notes.md +9 -1
  9. data/lib/hammer_cli.rb +0 -1
  10. data/lib/hammer_cli/abstract.rb +44 -13
  11. data/lib/hammer_cli/exception_handler.rb +1 -1
  12. data/lib/hammer_cli/help/definition.rb +55 -0
  13. data/lib/hammer_cli/help/definition/abstract_item.rb +38 -0
  14. data/lib/hammer_cli/help/definition/list.rb +53 -0
  15. data/lib/hammer_cli/help/definition/section.rb +36 -0
  16. data/lib/hammer_cli/help/definition/text.rb +21 -0
  17. data/lib/hammer_cli/help/text_builder.rb +26 -49
  18. data/lib/hammer_cli/i18n.rb +0 -1
  19. data/lib/hammer_cli/options/option_collector.rb +12 -9
  20. data/lib/hammer_cli/options/option_processor.rb +17 -0
  21. data/lib/hammer_cli/options/processor_list.rb +37 -0
  22. data/lib/hammer_cli/options/sources/base.rb +17 -0
  23. data/lib/hammer_cli/options/sources/command_line.rb +3 -1
  24. data/lib/hammer_cli/options/sources/saved_defaults.rb +3 -1
  25. data/lib/hammer_cli/options/validators/base.rb +20 -0
  26. data/lib/hammer_cli/options/validators/dsl.rb +160 -0
  27. data/lib/hammer_cli/options/validators/dsl_block_validator.rb +19 -0
  28. data/lib/hammer_cli/output/adapter/csv.rb +11 -11
  29. data/lib/hammer_cli/output/adapter/tree_structure.rb +5 -3
  30. data/lib/hammer_cli/output/definition.rb +42 -4
  31. data/lib/hammer_cli/output/dsl.rb +4 -2
  32. data/lib/hammer_cli/output/fields.rb +9 -2
  33. data/lib/hammer_cli/testing/messages.rb +6 -6
  34. data/lib/hammer_cli/utils.rb +15 -0
  35. data/lib/hammer_cli/version.rb +1 -1
  36. data/locale/ca/LC_MESSAGES/hammer-cli.mo +0 -0
  37. data/locale/de/LC_MESSAGES/hammer-cli.mo +0 -0
  38. data/locale/en/LC_MESSAGES/hammer-cli.mo +0 -0
  39. data/locale/en_GB/LC_MESSAGES/hammer-cli.mo +0 -0
  40. data/locale/es/LC_MESSAGES/hammer-cli.mo +0 -0
  41. data/locale/fr/LC_MESSAGES/hammer-cli.mo +0 -0
  42. data/locale/it/LC_MESSAGES/hammer-cli.mo +0 -0
  43. data/locale/ja/LC_MESSAGES/hammer-cli.mo +0 -0
  44. data/locale/ko/LC_MESSAGES/hammer-cli.mo +0 -0
  45. data/locale/pt_BR/LC_MESSAGES/hammer-cli.mo +0 -0
  46. data/locale/ru/LC_MESSAGES/hammer-cli.mo +0 -0
  47. data/locale/zh_CN/LC_MESSAGES/hammer-cli.mo +0 -0
  48. data/locale/zh_TW/LC_MESSAGES/hammer-cli.mo +0 -0
  49. data/test/unit/abstract_test.rb +70 -5
  50. data/test/unit/exception_handler_test.rb +1 -1
  51. data/test/unit/help/definition/abstract_item_test.rb +33 -0
  52. data/test/unit/help/definition/list_test.rb +17 -0
  53. data/test/unit/help/definition/section_test.rb +25 -0
  54. data/test/unit/help/definition/text_test.rb +11 -0
  55. data/test/unit/help/definition_test.rb +236 -0
  56. data/test/unit/help/text_builder_test.rb +170 -1
  57. data/test/unit/options/option_collector_test.rb +18 -9
  58. data/test/unit/options/processor_list_test.rb +70 -0
  59. data/test/unit/{validator_test.rb → options/validators/dsl_test.rb} +57 -93
  60. data/test/unit/output/adapter/abstract_test.rb +3 -0
  61. data/test/unit/output/adapter/base_test.rb +5 -0
  62. data/test/unit/output/adapter/csv_test.rb +3 -0
  63. data/test/unit/output/adapter/json_test.rb +12 -0
  64. data/test/unit/output/adapter/table_test.rb +5 -0
  65. data/test/unit/output/adapter/yaml_test.rb +11 -0
  66. data/test/unit/output/definition_test.rb +221 -1
  67. data/test/unit/utils_test.rb +23 -0
  68. metadata +31 -5
  69. data/lib/hammer_cli/validator.rb +0 -172
@@ -1,7 +1,9 @@
1
+ require_relative './base'
2
+
1
3
  module HammerCLI
2
4
  module Options
3
5
  module Sources
4
- class CommandLine
6
+ class CommandLine < Base
5
7
  def initialize(command)
6
8
  @command = command
7
9
  end
@@ -1,7 +1,9 @@
1
+ require_relative './base'
2
+
1
3
  module HammerCLI
2
4
  module Options
3
5
  module Sources
4
- class SavedDefaults
6
+ class SavedDefaults < Base
5
7
  def initialize(defaults, logger)
6
8
  @defaults = defaults
7
9
  @logger = logger
@@ -0,0 +1,20 @@
1
+ require_relative '../option_processor'
2
+
3
+ module HammerCLI
4
+ module Options
5
+ module Validators
6
+ class ValidationError < StandardError
7
+ end
8
+
9
+ class Base < HammerCLI::Options::OptionProcessor
10
+ def process(defined_options, result)
11
+ run(defined_options, result)
12
+ result
13
+ end
14
+
15
+ def run(defined_options, result)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,160 @@
1
+ module HammerCLI
2
+ module Options
3
+ module Validators
4
+ class DSL
5
+ class BaseConstraint
6
+ attr_reader :rejected_msg, :required_msg
7
+
8
+ def initialize(option_definitions, option_values, to_check)
9
+ @to_check = to_check
10
+ @rejected_msg = ""
11
+ @required_msg = ""
12
+
13
+ @option_values = option_values
14
+ @options = option_definitions.inject({}) do |hash, opt|
15
+ hash.update({opt.attribute_name => opt})
16
+ end
17
+ end
18
+
19
+ def rejected(args={})
20
+ msg = args[:msg] || rejected_msg % option_switches.join(", ")
21
+ raise HammerCLI::Options::Validators::ValidationError.new(msg) if exist?
22
+ end
23
+
24
+ def required(args={})
25
+ msg = args[:msg] || required_msg % option_switches.join(", ")
26
+ raise HammerCLI::Options::Validators::ValidationError.new(msg) unless exist?
27
+ end
28
+
29
+ def exist?
30
+ raise NotImplementedError
31
+ end
32
+
33
+ protected
34
+
35
+ def get_option(name)
36
+ name = name.to_s
37
+ raise _("Unknown option name '%s'.") % name unless @options.has_key? name
38
+ @options[name]
39
+ end
40
+
41
+ def get_option_value(name)
42
+ @option_values[name] || @option_values[name.to_s]
43
+ end
44
+
45
+ def option_passed?(option_name)
46
+ !get_option_value(option_name).nil?
47
+ end
48
+
49
+ def option_switches(opts=nil)
50
+ opts ||= @to_check
51
+ opts.collect do |option_name|
52
+ get_option(option_name).long_switch || get_option(option_name).switches.first
53
+ end
54
+ end
55
+ end
56
+
57
+ class AllConstraint < BaseConstraint
58
+ def initialize(options, option_values, to_check)
59
+ super
60
+ @rejected_msg = _("You can't set all options %s at one time.")
61
+ @required_msg = _("Options %s are required.")
62
+ end
63
+
64
+ def exist?
65
+ @to_check.each do |opt|
66
+ return false unless option_passed?(opt)
67
+ end
68
+ return true
69
+ end
70
+ end
71
+
72
+ class OneOptionConstraint < AllConstraint
73
+ def initialize(options, option_values, to_check)
74
+ super(options, option_values, [to_check])
75
+ @rejected_msg = _("You can't set option %s.")
76
+ @required_msg = _("Option %s is required.")
77
+ end
78
+
79
+ def value
80
+ get_option_value(@to_check[0])
81
+ end
82
+ end
83
+
84
+ class AnyConstraint < BaseConstraint
85
+ def initialize(options, option_values, to_check)
86
+ super
87
+ @rejected_msg = _("You can't set any of options %s.")
88
+ @required_msg = _("At least one of options %s is required.")
89
+ end
90
+
91
+ def exist?
92
+ @to_check.each do |opt|
93
+ return true if option_passed?(opt)
94
+ end
95
+ return @to_check.empty?
96
+ end
97
+ end
98
+
99
+
100
+ class OneOfConstraint < BaseConstraint
101
+ def initialize(options, option_values, to_check)
102
+ raise 'Set at least one expected option' if to_check.empty?
103
+ super
104
+ end
105
+
106
+ def rejected
107
+ raise NotImplementedError, '#rejected is unsupported for OneOfConstraint'
108
+ end
109
+
110
+ def required_msg
111
+ case count_present_options
112
+ when 0
113
+ _("One of options %s is required.")
114
+ when 1
115
+ ''
116
+ else
117
+ _("Only one of options %s can be set.")
118
+ end
119
+ end
120
+
121
+ def exist?
122
+ return count_present_options == 1
123
+ end
124
+
125
+ protected
126
+ def count_present_options
127
+ @to_check.count do |opt|
128
+ option_passed?(opt)
129
+ end
130
+ end
131
+ end
132
+
133
+ def initialize(options, option_values)
134
+ @options = options
135
+ @option_values = option_values
136
+ end
137
+
138
+ def all(*to_check)
139
+ AllConstraint.new(@options, @option_values, to_check.flatten(1))
140
+ end
141
+
142
+ def option(to_check)
143
+ OneOptionConstraint.new(@options, @option_values, to_check)
144
+ end
145
+
146
+ def any(*to_check)
147
+ AnyConstraint.new(@options, @option_values, to_check.flatten(1))
148
+ end
149
+
150
+ def one_of(*to_check)
151
+ OneOfConstraint.new(@options, @option_values, to_check.flatten(1))
152
+ end
153
+
154
+ def run(&block)
155
+ self.instance_eval &block
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,19 @@
1
+ require_relative './base'
2
+ require_relative './dsl'
3
+
4
+ module HammerCLI
5
+ module Options
6
+ module Validators
7
+ class DSLBlockValidator < Base
8
+ def initialize(&block)
9
+ @validation_block = block
10
+ end
11
+
12
+ def run(options, option_values)
13
+ dsl = DSL.new(options, option_values)
14
+ dsl.run(&@validation_block)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -165,20 +165,20 @@ module HammerCLI::Output::Adapter
165
165
 
166
166
  def print_message(msg, msg_params={})
167
167
  csv_string = generate do |csv|
168
- id = msg_params["id"] || msg_params[:id]
169
- name = msg_params["name"] || msg_params[:name]
170
-
171
168
  labels = [_("Message")]
172
169
  data = [msg.format(msg_params)]
173
170
 
174
- if id
175
- labels << _("Id")
176
- data << id
177
- end
178
-
179
- if name
180
- labels << _("Name")
181
- data << name
171
+ unless msg_params.nil?
172
+ id = msg_params["id"] || msg_params[:id]
173
+ name = msg_params["name"] || msg_params[:name]
174
+ if id
175
+ labels << _("Id")
176
+ data << id
177
+ end
178
+ if name
179
+ labels << _("Name")
180
+ data << name
181
+ end
182
182
  end
183
183
 
184
184
  csv << labels
@@ -19,12 +19,14 @@ module HammerCLI::Output::Adapter
19
19
  end
20
20
 
21
21
  def prepare_message(msg, msg_params = {})
22
- id = msg_params['id'] || msg_params[:id]
23
- name = msg_params['name'] || msg_params[:name]
24
-
25
22
  data = {
26
23
  capitalize(:message) => msg.format(msg_params)
27
24
  }
25
+ return data if msg_params.nil?
26
+
27
+ id = msg_params['id'] || msg_params[:id]
28
+ name = msg_params['name'] || msg_params[:name]
29
+
28
30
  data[capitalize(:id)] = id unless id.nil?
29
31
  data[capitalize(:name)] = name unless name.nil?
30
32
  data
@@ -1,21 +1,59 @@
1
1
  module HammerCLI::Output
2
-
3
2
  class Definition
4
-
5
3
  attr_accessor :fields
6
4
 
7
5
  def initialize
8
6
  @fields = []
9
7
  end
10
8
 
11
- def append(fields)
9
+ def append(fields = nil, &block)
10
+ fields = [fields].compact unless fields.is_a?(Array)
12
11
  @fields += fields
12
+ return @fields unless block_given?
13
+ dsl = Dsl.new
14
+ dsl.build(&block)
15
+ @fields += dsl.fields
16
+ end
17
+
18
+ def find_field(field_id)
19
+ @fields[field_index(field_id)]
20
+ end
21
+
22
+ def insert(mode, field_id, fields = nil, &block)
23
+ definition = self.class.new
24
+ definition.append(fields, &block)
25
+ HammerCLI.insert_relative(@fields, mode, field_index(field_id), *definition.fields)
26
+ end
27
+
28
+ def at(path = [])
29
+ path = [path] unless path.is_a? Array
30
+ return self if path.empty?
31
+
32
+ field = find_field(path[0])
33
+
34
+ unless field.respond_to?(:output_definition)
35
+ raise ArgumentError, "Field #{path[0]} doesn't have nested output definition"
36
+ end
37
+
38
+ field.output_definition.at(path[1..-1])
39
+ end
40
+
41
+ def clear
42
+ @fields = []
13
43
  end
14
44
 
15
45
  def empty?
16
46
  @fields.empty?
17
47
  end
18
48
 
19
- end
49
+ private
20
50
 
51
+ def field_index(field_id)
52
+ index = @fields.find_index do |f|
53
+ f.match_id?(field_id)
54
+ end
55
+ raise ArgumentError, "Field #{field_id} not found" if index.nil?
56
+ index
57
+ end
58
+ end
21
59
  end
@@ -19,8 +19,10 @@ module HammerCLI::Output
19
19
 
20
20
  def field(key, label, type=nil, options={}, &block)
21
21
  options[:path] = current_path.clone
22
- options[:path] << key if !key.nil?
23
-
22
+ unless key.nil?
23
+ options[:path] << key
24
+ options[:key] = key
25
+ end
24
26
  options[:label] = label
25
27
  type ||= Fields::Field
26
28
  custom_field type, options, &block
@@ -3,9 +3,8 @@ require 'hammer_cli/output/dsl'
3
3
  module Fields
4
4
 
5
5
  class Field
6
-
7
- attr_reader :label
8
6
  attr_reader :path
7
+ attr_accessor :label
9
8
 
10
9
  def initialize(options={})
11
10
  @hide_blank = options[:hide_blank].nil? ? false : options[:hide_blank]
@@ -15,6 +14,14 @@ module Fields
15
14
  @options = options
16
15
  end
17
16
 
17
+ def id
18
+ @options[:id] || @options[:key] || @label
19
+ end
20
+
21
+ def match_id?(field_id)
22
+ @options[:id] == field_id || @options[:key] == field_id || @label == _(field_id)
23
+ end
24
+
18
25
  def hide_blank?
19
26
  @hide_blank
20
27
  end
@@ -33,19 +33,19 @@ module HammerCLI
33
33
  refute opt.description.end_with?('.'), "Description for option #{opt.long_switch} in #{cmd} ends with '.'"
34
34
  end
35
35
 
36
- def check_command_messages(cmd)
36
+ def check_command_messages(cmd, except: [])
37
37
  cmd.recognised_options.each do |opt|
38
38
  check_option_description(cmd, opt)
39
39
  end
40
- refute_msg_period(cmd, :desc)
41
- assert_msg_period(cmd, :success_message)
42
- refute_msg_period(cmd, :failure_message)
40
+ refute_msg_period(cmd, :desc) unless except.include?(:desc)
41
+ assert_msg_period(cmd, :success_message) unless except.include?(:success_message)
42
+ refute_msg_period(cmd, :failure_message) unless except.include?(:failure_message)
43
43
  end
44
44
 
45
- def check_all_command_messages(main_cmd, parent=HammerCLI::AbstractCommand)
45
+ def check_all_command_messages(main_cmd, parent=HammerCLI::AbstractCommand, except: {})
46
46
  all_subcommands(main_cmd, parent).each do |cmd|
47
47
  it "test messages of #{cmd}" do
48
- check_command_messages(cmd)
48
+ check_command_messages(cmd, except: (except[cmd.to_s] || []))
49
49
  end
50
50
  end
51
51
  end
@@ -96,4 +96,19 @@ module HammerCLI
96
96
  end
97
97
  result
98
98
  end
99
+
100
+ def self.insert_relative(array, mode, idx, *new_items)
101
+ case mode
102
+ when :prepend
103
+ idx = 0
104
+ when :append
105
+ idx = -1
106
+ when :after
107
+ idx += 1
108
+ when :replace
109
+ array.delete_at(idx)
110
+ end
111
+
112
+ array.insert(idx, *new_items)
113
+ end
99
114
  end
@@ -1,5 +1,5 @@
1
1
  module HammerCLI
2
2
  def self.version
3
- @version ||= Gem::Version.new '0.15.1'
3
+ @version ||= Gem::Version.new '0.16.0'
4
4
  end
5
5
  end