hammer_cli 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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: