hammer_cli 0.0.4

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 (38) hide show
  1. data/LICENSE +5 -0
  2. data/README.md +105 -0
  3. data/bin/hammer +53 -0
  4. data/config/cli_config.template.yml +14 -0
  5. data/doc/design.png +0 -0
  6. data/doc/design.uml +24 -0
  7. data/hammer_cli_complete +13 -0
  8. data/lib/hammer_cli/abstract.rb +95 -0
  9. data/lib/hammer_cli/apipie/command.rb +75 -0
  10. data/lib/hammer_cli/apipie/options.rb +97 -0
  11. data/lib/hammer_cli/apipie/read_command.rb +58 -0
  12. data/lib/hammer_cli/apipie/resource.rb +54 -0
  13. data/lib/hammer_cli/apipie/write_command.rb +35 -0
  14. data/lib/hammer_cli/apipie.rb +3 -0
  15. data/lib/hammer_cli/autocompletion.rb +46 -0
  16. data/lib/hammer_cli/exception_handler.rb +69 -0
  17. data/lib/hammer_cli/exit_codes.rb +23 -0
  18. data/lib/hammer_cli/logger.rb +50 -0
  19. data/lib/hammer_cli/logger_watch.rb +14 -0
  20. data/lib/hammer_cli/main.rb +53 -0
  21. data/lib/hammer_cli/messages.rb +55 -0
  22. data/lib/hammer_cli/option_formatters.rb +13 -0
  23. data/lib/hammer_cli/output/adapter/abstract.rb +27 -0
  24. data/lib/hammer_cli/output/adapter/base.rb +143 -0
  25. data/lib/hammer_cli/output/adapter/silent.rb +17 -0
  26. data/lib/hammer_cli/output/adapter/table.rb +53 -0
  27. data/lib/hammer_cli/output/adapter.rb +6 -0
  28. data/lib/hammer_cli/output/definition.rb +17 -0
  29. data/lib/hammer_cli/output/dsl.rb +56 -0
  30. data/lib/hammer_cli/output/fields.rb +128 -0
  31. data/lib/hammer_cli/output/output.rb +27 -0
  32. data/lib/hammer_cli/output.rb +6 -0
  33. data/lib/hammer_cli/settings.rb +48 -0
  34. data/lib/hammer_cli/shell.rb +49 -0
  35. data/lib/hammer_cli/validator.rb +114 -0
  36. data/lib/hammer_cli/version.rb +5 -0
  37. data/lib/hammer_cli.rb +13 -0
  38. metadata +189 -0
@@ -0,0 +1,128 @@
1
+ require 'hammer_cli/output/dsl'
2
+
3
+ module HammerCLI::Output
4
+
5
+
6
+ class Field
7
+
8
+ def initialize(options={})
9
+ end
10
+
11
+ def get_value(data)
12
+ end
13
+
14
+ end
15
+
16
+ class LabeledField < Field
17
+
18
+ attr_reader :label
19
+
20
+ def initialize(options={})
21
+ @label = options[:label]
22
+ end
23
+ end
24
+
25
+ class DataField < LabeledField
26
+
27
+ attr_reader :path
28
+
29
+ def initialize(options={})
30
+ @path = options[:path] || []
31
+ super(options)
32
+ end
33
+
34
+ def get_value(data)
35
+ follow_path(data, path || [])
36
+ end
37
+
38
+ private
39
+
40
+ def follow_path(record, path)
41
+ record = symbolize_hash_keys(record)
42
+
43
+ path.inject(record) do |record, path_key|
44
+ if record.has_key? path_key.to_sym
45
+ record[path_key.to_sym]
46
+ else
47
+ return nil
48
+ end
49
+ end
50
+ end
51
+
52
+ def symbolize_hash_keys(h)
53
+ if h.is_a? Hash
54
+ return h.inject({}){|result,(k,v)| result.update k.to_sym => symbolize_hash_keys(v)}
55
+ elsif h.is_a? Array
56
+ return h.collect{|item| symbolize_hash_keys(item)}
57
+ else
58
+ h
59
+ end
60
+ end
61
+
62
+ end
63
+
64
+
65
+ module Fields
66
+
67
+
68
+ class Date < HammerCLI::Output::DataField
69
+ end
70
+
71
+ class OSName < HammerCLI::Output::DataField
72
+ end
73
+
74
+ class List < HammerCLI::Output::DataField
75
+ end
76
+
77
+ class KeyValue < HammerCLI::Output::DataField
78
+ end
79
+
80
+ class Server < HammerCLI::Output::DataField
81
+ end
82
+
83
+ class Joint < HammerCLI::Output::DataField
84
+ def initialize(options={}, &block)
85
+ super(options)
86
+ @attributes = options[:attributes] || []
87
+ end
88
+
89
+ attr_reader :attributes
90
+ end
91
+
92
+ class Label < HammerCLI::Output::LabeledField
93
+
94
+ def initialize(options={}, &block)
95
+ super(options)
96
+ dsl = HammerCLI::Output::Dsl.new :path => options[:path]
97
+ dsl.build &block if block_given?
98
+
99
+ self.output_definition.append dsl.fields
100
+ end
101
+
102
+ def output_definition
103
+ @output_definition ||= HammerCLI::Output::Definition.new
104
+ @output_definition
105
+ end
106
+
107
+ end
108
+
109
+ class Collection < HammerCLI::Output::DataField
110
+
111
+ def initialize(options={}, &block)
112
+ super(options)
113
+ dsl = HammerCLI::Output::Dsl.new
114
+ dsl.build &block if block_given?
115
+
116
+ self.output_definition.append dsl.fields
117
+ end
118
+
119
+ def output_definition
120
+ @output_definition ||= HammerCLI::Output::Definition.new
121
+ @output_definition
122
+ end
123
+
124
+ end
125
+
126
+ end
127
+
128
+ end
@@ -0,0 +1,27 @@
1
+ module HammerCLI::Output
2
+ class Output
3
+
4
+ attr_accessor :adapter
5
+ attr_reader :definition
6
+
7
+ def initialize options={}
8
+ @adapter = options[:adapter] || HammerCLI::Output::Adapter::Base.new
9
+ @definition = options[:definition] || HammerCLI::Output::Definition.new
10
+ end
11
+
12
+ def print_message msg
13
+ adapter.print_message(msg.to_s)
14
+ end
15
+
16
+ def print_error msg, details=nil
17
+ adapter.print_error(msg.to_s, details)
18
+ end
19
+
20
+ def print_records records, heading=nil
21
+ records = [records] unless records.kind_of?(Array)
22
+
23
+ adapter.print_records(definition.fields, records, heading)
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,6 @@
1
+ require File.join(File.dirname(__FILE__), 'output/output')
2
+ require File.join(File.dirname(__FILE__), 'output/fields')
3
+ require File.join(File.dirname(__FILE__), 'output/adapter')
4
+ require File.join(File.dirname(__FILE__), 'output/definition')
5
+ require File.join(File.dirname(__FILE__), 'output/dsl')
6
+
@@ -0,0 +1,48 @@
1
+ require 'yaml'
2
+ require 'logging'
3
+
4
+ module HammerCLI
5
+
6
+ class Settings
7
+
8
+ def self.[] key
9
+ settings[key.to_sym]
10
+ end
11
+
12
+ def self.load_from_file files
13
+ files.reverse.each do |path|
14
+ full_path = File.expand_path path
15
+ if File.exists? full_path
16
+ config = YAML::load(File.open(full_path))
17
+ if config
18
+ load(config)
19
+ path_history << full_path
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ def self.load settings_hash
26
+ settings.merge! settings_hash.inject({}){ |sym_hash,(k,v)| sym_hash[k.to_sym] = v; sym_hash }
27
+ end
28
+
29
+ def self.clear
30
+ settings.clear
31
+ path_history.clear
32
+ end
33
+
34
+ def self.path_history
35
+ @path_history ||= []
36
+ @path_history
37
+ end
38
+
39
+ private
40
+ def self.settings
41
+ @settings_hash ||= {}
42
+ @settings_hash
43
+ end
44
+
45
+ end
46
+
47
+
48
+ end
@@ -0,0 +1,49 @@
1
+ require 'hammer_cli/abstract'
2
+ require 'readline'
3
+
4
+ module HammerCLI
5
+
6
+ class ShellCommand < AbstractCommand
7
+
8
+ def execute
9
+ Readline.completion_append_character = " "
10
+ Readline.completer_word_break_characters = ''
11
+ Readline.completion_proc = complete_proc
12
+
13
+ stty_save = `stty -g`.chomp
14
+
15
+ begin
16
+ while line = Readline.readline('hammer> ', true)
17
+ HammerCLI::MainCommand.run('hammer', line.split) unless line.start_with? 'shell'
18
+ end
19
+ rescue Interrupt => e
20
+ puts
21
+ system('stty', stty_save) # Restore
22
+ exit
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def common_prefix(results)
29
+ results.delete_if{ |r| !r[0].start_with?(results[0][0][0]) }.length == results.length
30
+ end
31
+
32
+ def complete_proc
33
+ Proc.new do |cpl|
34
+ res = HammerCLI::MainCommand.autocomplete(cpl.split)
35
+ # if there is one result or if results have common prefix
36
+ # readline tries to replace current input with results
37
+ # thus we should join the results with the start of the line
38
+ if res.length == 1 || common_prefix(res)
39
+ res.map { |r| r.delete_if{ |e| e == '' }.reverse.join(' ') }
40
+ else
41
+ res.map{ |e| e[0] }
42
+ end
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ HammerCLI::MainCommand.subcommand "shell", "Interactive Shell", HammerCLI::ShellCommand
49
+ end
@@ -0,0 +1,114 @@
1
+
2
+ module HammerCLI
3
+
4
+ class Validator
5
+
6
+ class ValidationError < StandardError
7
+ end
8
+
9
+ class BaseConstraint
10
+
11
+ attr_reader :rejected_msg, :required_msg
12
+
13
+ def initialize(options, to_check)
14
+ @to_check = to_check
15
+ @rejected_msg = ""
16
+ @required_msg = ""
17
+
18
+ @options = options.inject({}) do |hash, opt|
19
+ hash.update({opt.attribute.attribute_name => opt})
20
+ end
21
+ end
22
+
23
+ def rejected(args={})
24
+ msg = args[:msg] || rejected_msg % option_switches.join(", ")
25
+ raise ValidationError.new(msg) if exist?
26
+ end
27
+
28
+ def required(args={})
29
+ msg = args[:msg] || required_msg % option_switches.join(", ")
30
+ raise ValidationError.new(msg) unless exist?
31
+ end
32
+
33
+ def exist?
34
+ raise NotImplementedError
35
+ end
36
+
37
+ protected
38
+
39
+ def get_option(name)
40
+ name = name.to_s
41
+ raise "Unknown option name '%s'" % name unless @options.has_key? name
42
+ @options[name]
43
+ end
44
+
45
+ def option_passed?(option_name)
46
+ !get_option(option_name).get.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).attribute.long_switch || get_option(option_name).attribute.switches.first
53
+ end
54
+ end
55
+
56
+ end
57
+
58
+ class AllConstraint < BaseConstraint
59
+
60
+ def initialize(options, to_check)
61
+ super(options, to_check)
62
+ @rejected_msg = "You can't set all options %s at one time"
63
+ @required_msg = "Options %s are required"
64
+ end
65
+
66
+ def exist?
67
+ @to_check.each do |opt|
68
+ return false unless option_passed?(opt)
69
+ end
70
+ return true
71
+ end
72
+ end
73
+
74
+
75
+ class AnyConstraint < BaseConstraint
76
+
77
+ def initialize(options, to_check)
78
+ super(options, to_check)
79
+ @rejected_msg = "You can't set any of options %s"
80
+ @required_msg = "At least one of options %s is required"
81
+ end
82
+
83
+ def exist?
84
+ @to_check.each do |opt|
85
+ return true if option_passed?(opt)
86
+ end
87
+ return @to_check.empty?
88
+ end
89
+ end
90
+
91
+
92
+ def initialize(options)
93
+ @options = options
94
+ end
95
+
96
+ def all(*to_check)
97
+ AllConstraint.new(@options, to_check)
98
+ end
99
+
100
+ def option(to_check)
101
+ all(to_check)
102
+ end
103
+
104
+ def any(*to_check)
105
+ AnyConstraint.new(@options, to_check)
106
+ end
107
+
108
+ def run(&block)
109
+ self.instance_eval &block
110
+ end
111
+
112
+ end
113
+
114
+ end
@@ -0,0 +1,5 @@
1
+ module HammerCLI
2
+ def self.version
3
+ @version ||= Gem::Version.new '0.0.4'
4
+ end
5
+ end
data/lib/hammer_cli.rb ADDED
@@ -0,0 +1,13 @@
1
+ require 'hammer_cli/version'
2
+ require 'hammer_cli/exit_codes'
3
+ require 'hammer_cli/settings'
4
+ require 'hammer_cli/validator'
5
+ require 'hammer_cli/abstract'
6
+ require 'hammer_cli/main'
7
+
8
+ require 'hammer_cli/output'
9
+ require 'hammer_cli/apipie'
10
+
11
+ # extend MainCommand
12
+ require 'hammer_cli/shell'
13
+
metadata ADDED
@@ -0,0 +1,189 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hammer_cli
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Martin Bačovský
9
+ - Tomáš Strachota
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2013-08-30 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: clamp
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
31
+ - !ruby/object:Gem::Dependency
32
+ name: rest-client
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: logging
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ - !ruby/object:Gem::Dependency
64
+ name: awesome_print
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ type: :runtime
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ - !ruby/object:Gem::Dependency
80
+ name: table_print
81
+ requirement: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ type: :runtime
88
+ prerelease: false
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ - !ruby/object:Gem::Dependency
96
+ name: highline
97
+ requirement: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: ! 'Hammer cli provides universal extendable CLI interface for ruby apps
112
+
113
+ '
114
+ email: mbacovsk@redhat.com
115
+ executables:
116
+ - hammer
117
+ extensions: []
118
+ extra_rdoc_files:
119
+ - README.md
120
+ - LICENSE
121
+ - hammer_cli_complete
122
+ - config/cli_config.template.yml
123
+ - doc/design.uml
124
+ - doc/design.png
125
+ files:
126
+ - lib/hammer_cli/output.rb
127
+ - lib/hammer_cli/option_formatters.rb
128
+ - lib/hammer_cli/abstract.rb
129
+ - lib/hammer_cli/apipie/write_command.rb
130
+ - lib/hammer_cli/apipie/command.rb
131
+ - lib/hammer_cli/apipie/options.rb
132
+ - lib/hammer_cli/apipie/read_command.rb
133
+ - lib/hammer_cli/apipie/resource.rb
134
+ - lib/hammer_cli/apipie.rb
135
+ - lib/hammer_cli/autocompletion.rb
136
+ - lib/hammer_cli/validator.rb
137
+ - lib/hammer_cli/exit_codes.rb
138
+ - lib/hammer_cli/version.rb
139
+ - lib/hammer_cli/logger_watch.rb
140
+ - lib/hammer_cli/main.rb
141
+ - lib/hammer_cli/settings.rb
142
+ - lib/hammer_cli/output/output.rb
143
+ - lib/hammer_cli/output/adapter/abstract.rb
144
+ - lib/hammer_cli/output/adapter/table.rb
145
+ - lib/hammer_cli/output/adapter/base.rb
146
+ - lib/hammer_cli/output/adapter/silent.rb
147
+ - lib/hammer_cli/output/dsl.rb
148
+ - lib/hammer_cli/output/adapter.rb
149
+ - lib/hammer_cli/output/definition.rb
150
+ - lib/hammer_cli/output/fields.rb
151
+ - lib/hammer_cli/logger.rb
152
+ - lib/hammer_cli/exception_handler.rb
153
+ - lib/hammer_cli/messages.rb
154
+ - lib/hammer_cli/shell.rb
155
+ - lib/hammer_cli.rb
156
+ - bin/hammer
157
+ - README.md
158
+ - LICENSE
159
+ - hammer_cli_complete
160
+ - config/cli_config.template.yml
161
+ - doc/design.uml
162
+ - doc/design.png
163
+ homepage: http://github.com/theforeman/hammer-cli
164
+ licenses:
165
+ - GPL-3
166
+ post_install_message:
167
+ rdoc_options: []
168
+ require_paths:
169
+ - lib
170
+ required_ruby_version: !ruby/object:Gem::Requirement
171
+ none: false
172
+ requirements:
173
+ - - ! '>='
174
+ - !ruby/object:Gem::Version
175
+ version: '0'
176
+ required_rubygems_version: !ruby/object:Gem::Requirement
177
+ none: false
178
+ requirements:
179
+ - - ! '>='
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ requirements: []
183
+ rubyforge_project:
184
+ rubygems_version: 1.8.23
185
+ signing_key:
186
+ specification_version: 3
187
+ summary: Universal command-line interface
188
+ test_files: []
189
+ has_rdoc: