kafo_wizards 0.0.1
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.
- checksums.yaml +7 -0
- data/LICENSE.txt +11 -0
- data/README.md +88 -0
- data/Rakefile +10 -0
- data/lib/kafo_wizards.rb +7 -0
- data/lib/kafo_wizards/abstract_wizard.rb +104 -0
- data/lib/kafo_wizards/entries.rb +9 -0
- data/lib/kafo_wizards/entries/abstract.rb +72 -0
- data/lib/kafo_wizards/entries/boolean.rb +15 -0
- data/lib/kafo_wizards/entries/button.rb +27 -0
- data/lib/kafo_wizards/entries/ip_address.rb +16 -0
- data/lib/kafo_wizards/entries/netmask.rb +25 -0
- data/lib/kafo_wizards/entries/password.rb +33 -0
- data/lib/kafo_wizards/entries/selector.rb +22 -0
- data/lib/kafo_wizards/entries/string.rb +12 -0
- data/lib/kafo_wizards/entries/string_or_file.rb +14 -0
- data/lib/kafo_wizards/exceptions.rb +12 -0
- data/lib/kafo_wizards/factory.rb +24 -0
- data/lib/kafo_wizards/highline.rb +8 -0
- data/lib/kafo_wizards/highline/abstract_renderer.rb +17 -0
- data/lib/kafo_wizards/highline/boolean_renderer.rb +21 -0
- data/lib/kafo_wizards/highline/button_renderer.rb +17 -0
- data/lib/kafo_wizards/highline/password_renderer.rb +24 -0
- data/lib/kafo_wizards/highline/selector_renderer.rb +32 -0
- data/lib/kafo_wizards/highline/string_or_file_renderer.rb +25 -0
- data/lib/kafo_wizards/highline/string_renderer.rb +23 -0
- data/lib/kafo_wizards/highline/wizard.rb +99 -0
- data/lib/kafo_wizards/version.rb +3 -0
- metadata +184 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0f658c648e658e6378f3051e127e57204ea368e3
|
4
|
+
data.tar.gz: d985f2ac7a37638007bd9f0ea649d0c26a936545
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6215f0b624883378e803fdd82d7608ba84d2de1dad1b18182b80b9052b5cf9065060b37cd679c5c6581febb234b7865bed15f5f43038179279448676d4b0d9c7
|
7
|
+
data.tar.gz: 53fdddf5193a3eee0782ad2759c2a5b6e150b475e038b1c8758dd501c98a7b7f9305f34acf042e7a94604c576aef172301b8f87aa5cba38a995059b22bfeb8f6
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
This program and entire repository is free software: you can redistribute it
|
2
|
+
and/or modify it under the terms of the GNU General Public License as
|
3
|
+
published by the Free Software Foundation, either version 3 of the License,
|
4
|
+
or any later version.
|
5
|
+
|
6
|
+
This program is distributed in the hope that it will be useful, but WITHOUT
|
7
|
+
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
8
|
+
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
9
|
+
|
10
|
+
You should have received a copy of the GNU General Public License along with
|
11
|
+
this program. If not, see http://www.gnu.org/licenses/.
|
data/README.md
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
# KafoWizards
|
2
|
+
|
3
|
+
|
4
|
+
With this gem it is possible to define form or wizard and display it to the user using one of the defined backends. The form definition is independent on the chosen backend so it can be changed freely. Currently only command line (highline) backend is implemented, YAD or web based backend is planed.
|
5
|
+
|
6
|
+
Warning: The code is still very unstable
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
gem 'kafo_wizards'
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install kafo_wizards
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
require 'kafo_wizards'
|
26
|
+
require 'awesome_print'
|
27
|
+
|
28
|
+
wizard = KafoWizards.wizard(:cli, 'Register',
|
29
|
+
:description => "Please provide credentials for a new account")
|
30
|
+
|
31
|
+
f = wizard.factory
|
32
|
+
|
33
|
+
wizard.entries = [
|
34
|
+
f.string(:username, :default_value => 'admin', :required => true),
|
35
|
+
f.password(:password, :label => 'Password', :confirmation_required => true, :required => true),
|
36
|
+
f.button(:register, :label => 'Register new account', :default => true),
|
37
|
+
f.button(:cancel, :default => false, :trigger_validation => false)
|
38
|
+
]
|
39
|
+
|
40
|
+
res = wizard.run
|
41
|
+
|
42
|
+
puts "Submitted with #{res.ai}"
|
43
|
+
puts "Values: #{wizard.values.ai}"
|
44
|
+
```
|
45
|
+
|
46
|
+
will render as:
|
47
|
+
|
48
|
+
```text
|
49
|
+
Register
|
50
|
+
*Username: 'admin'
|
51
|
+
*Password: **********
|
52
|
+
|
53
|
+
Please provide credentials for a new account
|
54
|
+
|
55
|
+
Available actions:
|
56
|
+
1. Register new account
|
57
|
+
2. Change Username
|
58
|
+
3. Change Password
|
59
|
+
4. Cancel
|
60
|
+
Your choice: 3
|
61
|
+
Enter new password: ********
|
62
|
+
Re-type new password: ********
|
63
|
+
|
64
|
+
Register
|
65
|
+
*Username: 'admin'
|
66
|
+
*Password: **********
|
67
|
+
|
68
|
+
Please provide credentials for a new account
|
69
|
+
|
70
|
+
Available actions:
|
71
|
+
1. Register new account
|
72
|
+
2. Change Username
|
73
|
+
3. Change Password
|
74
|
+
4. Cancel
|
75
|
+
Your choice: 1
|
76
|
+
Submitted with :register
|
77
|
+
Values: {
|
78
|
+
:username => "admin",
|
79
|
+
:password => "changeme"
|
80
|
+
}
|
81
|
+
|
82
|
+
```
|
83
|
+
|
84
|
+
For more examples look into `doc/examples/` directory.
|
85
|
+
|
86
|
+
# License
|
87
|
+
|
88
|
+
This project is licensed under the GPLv3+.
|
data/Rakefile
ADDED
data/lib/kafo_wizards.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module KafoWizards
|
4
|
+
class AbstractWizard
|
5
|
+
attr_reader :header, :description, :logger
|
6
|
+
attr_accessor :entries, :renderers, :interactive, :validators
|
7
|
+
def initialize(header, options = {})
|
8
|
+
@header = header
|
9
|
+
@interactive = options.fetch(:interactive, true)
|
10
|
+
@entries = options.fetch(:entries, [])
|
11
|
+
@description = options.fetch(:description, '')
|
12
|
+
@renderers = options.fetch(:renderers, self.class.default_renderers)
|
13
|
+
@validators = options.fetch(:validators, [])
|
14
|
+
@validators << lambda { |values| check_required_entries(values) }
|
15
|
+
@logger = options.fetch(:logger) do |l|
|
16
|
+
logger = Logger.new(STDERR)
|
17
|
+
logger.level = Logger::ERROR
|
18
|
+
logger
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def run
|
23
|
+
if @interactive
|
24
|
+
choice = execute_menu
|
25
|
+
else
|
26
|
+
choice = nil
|
27
|
+
default_button = buttons.find { |b| b.default? }
|
28
|
+
choice = default_button.name if default_button
|
29
|
+
end
|
30
|
+
choice
|
31
|
+
end
|
32
|
+
|
33
|
+
def execute_menu
|
34
|
+
end
|
35
|
+
|
36
|
+
def buttons
|
37
|
+
@entries.select { |e| e.class >= KafoWizards::Entries::ButtonEntry }
|
38
|
+
end
|
39
|
+
|
40
|
+
def triggers
|
41
|
+
buttons.inject([]) do |b_names, b|
|
42
|
+
b_names << b.name if b.trigger_validation?
|
43
|
+
b_names
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def values
|
48
|
+
@entries.inject({}) do |vals, entry|
|
49
|
+
vals[entry.name] = entry.value unless entry.class >= KafoWizards::Entries::ButtonEntry
|
50
|
+
vals
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def update(values = {})
|
55
|
+
|
56
|
+
entries.each do |entry|
|
57
|
+
entry.update(values[entry.name]) unless values[entry.name].nil?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def validate(values)
|
62
|
+
errors = []
|
63
|
+
validated = @validators.inject(values) do |result, lam|
|
64
|
+
begin
|
65
|
+
lam.call(result)
|
66
|
+
rescue ValidationError => e
|
67
|
+
errors += e.messages
|
68
|
+
result
|
69
|
+
end
|
70
|
+
end
|
71
|
+
raise ValidationError.new errors unless errors.empty?
|
72
|
+
validated
|
73
|
+
end
|
74
|
+
|
75
|
+
def factory
|
76
|
+
Factory.new(self)
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.default_renderers
|
80
|
+
@default_renderers ||= {}
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.register_default_renderer(display_type, renderer)
|
84
|
+
default_renderers[display_type] = renderer
|
85
|
+
end
|
86
|
+
|
87
|
+
protected
|
88
|
+
|
89
|
+
def check_required_entries(values)
|
90
|
+
messages = entries.inject([]) do |messages, e|
|
91
|
+
messages << "#{e.label} must be present" if e.required? && values[e.name].nil?
|
92
|
+
messages
|
93
|
+
end
|
94
|
+
raise ValidationError.new(messages) unless messages.empty?
|
95
|
+
values
|
96
|
+
end
|
97
|
+
|
98
|
+
def call_renderer_for_entry(render_method, entry)
|
99
|
+
display_type = entry.display_type(true).find { |dt| @renderers.has_key?(dt) && @renderers[dt].respond_to?(render_method) }
|
100
|
+
@renderers[display_type].send(render_method, entry) if display_type
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'kafo_wizards/entries/abstract'
|
2
|
+
require 'kafo_wizards/entries/string'
|
3
|
+
require 'kafo_wizards/entries/string_or_file'
|
4
|
+
require 'kafo_wizards/entries/button'
|
5
|
+
require 'kafo_wizards/entries/password'
|
6
|
+
require 'kafo_wizards/entries/boolean'
|
7
|
+
require 'kafo_wizards/entries/ip_address'
|
8
|
+
require 'kafo_wizards/entries/netmask'
|
9
|
+
require 'kafo_wizards/entries/selector'
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module KafoWizards::Entries
|
2
|
+
class AbstractEntry
|
3
|
+
attr_reader :name, :default_value, :value, :label
|
4
|
+
attr_accessor :description, :validators, :parent, :post_hook, :pre_hook
|
5
|
+
|
6
|
+
def initialize(name, options={})
|
7
|
+
@name = name
|
8
|
+
@value = @default_value = options.fetch(:default_value, nil)
|
9
|
+
@label = options.fetch(:label, @name.to_s.gsub('_', ' ').capitalize)
|
10
|
+
@description = options.fetch(:description, '')
|
11
|
+
@validators = options.fetch(:validators, [])
|
12
|
+
@required = !!options.fetch(:required, false)
|
13
|
+
@parent = options.fetch(:parent, nil)
|
14
|
+
@post_hook = options.fetch(:post_hook, nil)
|
15
|
+
@pre_hook = options.fetch(:pre_hook, nil)
|
16
|
+
end
|
17
|
+
|
18
|
+
def display_type(with_ancestry=false)
|
19
|
+
classes = self.class.ancestors.select { |cls| cls.name =~ /Entry\Z/ }
|
20
|
+
if with_ancestry
|
21
|
+
result = classes.map { |cls| class_to_underscore(cls.name) }
|
22
|
+
else
|
23
|
+
result = class_to_underscore(classes.first.name)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def required?
|
28
|
+
@required
|
29
|
+
end
|
30
|
+
|
31
|
+
def call_post_hook
|
32
|
+
post_hook.call(self) if post_hook
|
33
|
+
end
|
34
|
+
|
35
|
+
def call_pre_hook
|
36
|
+
pre_hook.call(self) if pre_hook
|
37
|
+
end
|
38
|
+
|
39
|
+
def update(new_value)
|
40
|
+
value = validate(new_value)
|
41
|
+
@value = @validators.inject(value) { |result, lam| lam.call(result) }
|
42
|
+
@value
|
43
|
+
end
|
44
|
+
|
45
|
+
def validate(new_value)
|
46
|
+
new_value
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.descendants
|
50
|
+
@descendants ||= []
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.inherited(child)
|
54
|
+
superclass.inherited(child) if self < KafoWizards::Entries::AbstractEntry
|
55
|
+
descendants << child
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.entry_type
|
59
|
+
:abstract
|
60
|
+
end
|
61
|
+
|
62
|
+
protected
|
63
|
+
|
64
|
+
def class_to_underscore(class_name)
|
65
|
+
class_name.split('::').last.gsub(/Entry/, '').
|
66
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
67
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
68
|
+
tr("-", "_").
|
69
|
+
downcase.to_sym
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module KafoWizards::Entries
|
2
|
+
|
3
|
+
class ButtonEntry < AbstractEntry
|
4
|
+
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
def initialize(name, options={})
|
8
|
+
super(name, options)
|
9
|
+
@default = !!options.fetch(:default, true)
|
10
|
+
@value = name
|
11
|
+
@trigger_validation = !!options.fetch(:trigger_validation, true)
|
12
|
+
end
|
13
|
+
|
14
|
+
def default?
|
15
|
+
@default
|
16
|
+
end
|
17
|
+
|
18
|
+
def trigger_validation?
|
19
|
+
@trigger_validation
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.entry_type
|
23
|
+
:button
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module KafoWizards::Entries
|
2
|
+
|
3
|
+
class IPAddressEntry < StringEntry
|
4
|
+
def validate(value)
|
5
|
+
if !(value =~ Resolv::IPv4::Regex)
|
6
|
+
raise KafoWizards::ValidationError.new("#{value} is not valid IP address")
|
7
|
+
end
|
8
|
+
value
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.entry_type
|
12
|
+
:ip_address
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
module KafoWizards::Entries
|
3
|
+
|
4
|
+
class NetmaskEntry < IPAddressEntry
|
5
|
+
def validate(value)
|
6
|
+
if value.to_s.include?('/')
|
7
|
+
begin
|
8
|
+
mask_len = value.split('/').last.to_i
|
9
|
+
value = IPAddr.new('255.255.255.255').mask(mask_len).to_s
|
10
|
+
rescue IPAddr::InvalidPrefixError => e
|
11
|
+
raise KafoWizards::ValidationError.new("#{value} is not valid netmask (#{e.message})")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
if !(value =~ Resolv::IPv4::Regex)
|
15
|
+
raise KafoWizards::ValidationError.new("#{value} is not valid netmask")
|
16
|
+
end
|
17
|
+
value
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.entry_type
|
21
|
+
:netmask
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module KafoWizards::Entries
|
2
|
+
|
3
|
+
class PasswordEntry < StringEntry
|
4
|
+
|
5
|
+
def initialize(name, options={})
|
6
|
+
super(name, options)
|
7
|
+
@confirmation_required = !!options.fetch(:confirmation_required, false)
|
8
|
+
end
|
9
|
+
|
10
|
+
def confirmation_required?
|
11
|
+
@confirmation_required
|
12
|
+
end
|
13
|
+
|
14
|
+
def validate(value)
|
15
|
+
if value.length < 8
|
16
|
+
raise KafoWizards::ValidationError.new("Password must be at least 8 characters long")
|
17
|
+
end
|
18
|
+
value
|
19
|
+
end
|
20
|
+
|
21
|
+
def update(value)
|
22
|
+
if confirmation_required? && (value[:password] != value[:password_confirmation])
|
23
|
+
raise KafoWizards::ValidationError.new("Password and confirmation do not match")
|
24
|
+
end
|
25
|
+
@value = validate(value[:password])
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.entry_type
|
29
|
+
:password
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module KafoWizards::Entries
|
2
|
+
|
3
|
+
class SelectorEntry < StringEntry
|
4
|
+
attr_accessor :options
|
5
|
+
|
6
|
+
def initialize(name, options={})
|
7
|
+
super(name, options)
|
8
|
+
@options = options.fetch(:options, {})
|
9
|
+
end
|
10
|
+
|
11
|
+
def validate(value)
|
12
|
+
raise KafoWizards::ValidationError.new("#{value} is not a valid option") unless options.include?(value)
|
13
|
+
value
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.entry_type
|
17
|
+
:selector
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module KafoWizards
|
2
|
+
|
3
|
+
def self.wizard(kind, header, options={})
|
4
|
+
HighLine::Wizard.new(header, options)
|
5
|
+
end
|
6
|
+
|
7
|
+
class Factory
|
8
|
+
|
9
|
+
def initialize(wizard=nil)
|
10
|
+
@wizard = wizard
|
11
|
+
end
|
12
|
+
|
13
|
+
def method_missing(meth, *args, &block)
|
14
|
+
if @wizard
|
15
|
+
args << {} unless args.last.class <= Hash
|
16
|
+
args[-1][:parent] = @wizard unless args[-1].has_key?(:parent)
|
17
|
+
end
|
18
|
+
|
19
|
+
entry_cls = KafoWizards::Entries::AbstractEntry.descendants.find { |ec| ec.entry_type == meth }
|
20
|
+
raise NameError.new "Unknown type of entry (#{meth.to_s})" unless entry_cls
|
21
|
+
entry_cls.new(*args)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require 'kafo_wizards/highline/wizard'
|
2
|
+
require 'kafo_wizards/highline/abstract_renderer'
|
3
|
+
require 'kafo_wizards/highline/boolean_renderer'
|
4
|
+
require 'kafo_wizards/highline/button_renderer'
|
5
|
+
require 'kafo_wizards/highline/string_renderer'
|
6
|
+
require 'kafo_wizards/highline/password_renderer'
|
7
|
+
require 'kafo_wizards/highline/string_or_file_renderer'
|
8
|
+
require 'kafo_wizards/highline/selector_renderer'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module KafoWizards
|
2
|
+
module HighLine
|
3
|
+
class AbstractRenderer
|
4
|
+
def render_value(entry)
|
5
|
+
end
|
6
|
+
|
7
|
+
def render_entry(entry)
|
8
|
+
end
|
9
|
+
|
10
|
+
def render_action(entry)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# register renderer to the highline wizard
|
15
|
+
Wizard.register_default_renderer :abstract, KafoWizards::HighLine::AbstractRenderer.new
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module KafoWizards
|
2
|
+
module HighLine
|
3
|
+
class BooleanRenderer < AbstractRenderer
|
4
|
+
def render_value(entry)
|
5
|
+
entry.value ? "#{::HighLine.color("Yes", :green)}" : "#{::HighLine.color("No", :red)}"
|
6
|
+
end
|
7
|
+
|
8
|
+
def render_entry(entry)
|
9
|
+
"Toggle #{entry.label}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def render_action(entry)
|
13
|
+
entry.update(!entry.value)
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# register renderer to the highline wizard
|
19
|
+
Wizard.register_default_renderer :boolean, KafoWizards::HighLine::BooleanRenderer.new
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module KafoWizards
|
2
|
+
module HighLine
|
3
|
+
class ButtonRenderer < AbstractRenderer
|
4
|
+
def render_entry(entry)
|
5
|
+
color = entry.default? ? :green : :red
|
6
|
+
"#{::HighLine.color(entry.label, color)}"
|
7
|
+
end
|
8
|
+
|
9
|
+
def render_action(entry)
|
10
|
+
entry.name
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# register renderer to the highline wizard
|
15
|
+
Wizard.register_default_renderer :button, KafoWizards::HighLine::ButtonRenderer.new
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module KafoWizards
|
2
|
+
module HighLine
|
3
|
+
|
4
|
+
class PasswordRenderer < StringRenderer
|
5
|
+
def render_value(entry)
|
6
|
+
"#{::HighLine.color("**********", :blue)}"
|
7
|
+
end
|
8
|
+
|
9
|
+
def render_action(entry)
|
10
|
+
password = ask("Enter new password: ") { |q| q.echo = "*" }
|
11
|
+
if !entry.confirmation_required?
|
12
|
+
entry.update(:password => password)
|
13
|
+
else
|
14
|
+
password_confirmation = ask("Re-type new password: ") { |q| q.echo = "*" }
|
15
|
+
entry.update(:password => password, :password_confirmation => password_confirmation)
|
16
|
+
end
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# register renderer to the highline wizard
|
22
|
+
Wizard.register_default_renderer :password, KafoWizards::HighLine::PasswordRenderer.new
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module KafoWizards
|
2
|
+
module HighLine
|
3
|
+
|
4
|
+
class SelectorRenderer < StringRenderer
|
5
|
+
def render_value(entry)
|
6
|
+
value = entry.options[entry.value].to_s
|
7
|
+
"'#{::HighLine.color(value, :blue)}'"
|
8
|
+
end
|
9
|
+
|
10
|
+
def render_entry(entry)
|
11
|
+
"Select #{entry.label}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def render_action(entry)
|
15
|
+
choose do |sel|
|
16
|
+
sel.header = ::HighLine.color("Available options", :white)
|
17
|
+
sel.prompt = "Select #{entry.label}: "
|
18
|
+
sel.select_by = :index
|
19
|
+
entry.options.each_pair do |opt, label|
|
20
|
+
sel.choice(label) do
|
21
|
+
entry.update(opt)
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# register renderer to the highline wizard
|
30
|
+
Wizard.register_default_renderer :selector, KafoWizards::HighLine::SelectorRenderer.new
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module KafoWizards
|
2
|
+
module HighLine
|
3
|
+
|
4
|
+
class StringOrFileRenderer < StringRenderer
|
5
|
+
def render_value(entry)
|
6
|
+
value = entry.value.to_s
|
7
|
+
if value.length > 40
|
8
|
+
value = entry.value[0..37]+'...'
|
9
|
+
end
|
10
|
+
"'#{::HighLine.color(value, :blue)}' (#{entry.value.to_s.length} bytes)"
|
11
|
+
end
|
12
|
+
|
13
|
+
def render_action(entry)
|
14
|
+
say entry.description if entry.description
|
15
|
+
key = ask("file path or key")
|
16
|
+
key = File.read(key) if File.exists?(key)
|
17
|
+
entry.update(key.chomp)
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# register renderer to the highline wizard
|
23
|
+
Wizard.register_default_renderer :string_or_file, KafoWizards::HighLine::StringOrFileRenderer.new
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module KafoWizards
|
2
|
+
module HighLine
|
3
|
+
class StringRenderer < AbstractRenderer
|
4
|
+
|
5
|
+
def render_value(entry)
|
6
|
+
"'#{::HighLine.color(entry.value.to_s, :blue)}'"
|
7
|
+
end
|
8
|
+
|
9
|
+
def render_entry(entry)
|
10
|
+
"Change #{entry.label}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def render_action(entry)
|
14
|
+
say entry.description if entry.description
|
15
|
+
key = ask("New value for #{entry.label}: ")
|
16
|
+
entry.update(key.chomp)
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
# register renderer to the highline wizard
|
21
|
+
Wizard.register_default_renderer :string, KafoWizards::HighLine::StringRenderer.new
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'highline/import'
|
2
|
+
|
3
|
+
module KafoWizards
|
4
|
+
module HighLine
|
5
|
+
class Wizard < AbstractWizard
|
6
|
+
|
7
|
+
def execute_menu
|
8
|
+
begin
|
9
|
+
choice = nil
|
10
|
+
loop do
|
11
|
+
say "\n"
|
12
|
+
say ::HighLine.color(header, :yellow) unless header.empty?
|
13
|
+
print_values
|
14
|
+
say "\n" + description
|
15
|
+
choice = print_menu
|
16
|
+
break unless choice.nil?
|
17
|
+
end
|
18
|
+
validate(values) if triggers.include? choice
|
19
|
+
choice
|
20
|
+
rescue KafoWizards::ValidationError => e
|
21
|
+
say ::HighLine.color("\nUnable to procedd due to following error(s):", :red)
|
22
|
+
say ::HighLine.color(format_errors(e.messages), :red)
|
23
|
+
say "\n"
|
24
|
+
retry
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def print_values
|
29
|
+
entries.each do |entry|
|
30
|
+
max_label_width = 25
|
31
|
+
next if (entry.class <= KafoWizards::Entries::ButtonEntry)
|
32
|
+
if entry.required?
|
33
|
+
label = ::HighLine.color(('*'+entry.label).rjust(max_label_width), :bold, :yellow)
|
34
|
+
else
|
35
|
+
label = entry.label.rjust(max_label_width)
|
36
|
+
end
|
37
|
+
say "#{label}: " + render_value(entry)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def print_menu
|
42
|
+
choose do |menu|
|
43
|
+
menu.header = ::HighLine.color("\nAvailable actions", :white)
|
44
|
+
menu.prompt = 'Your choice: '
|
45
|
+
menu.select_by = :index
|
46
|
+
|
47
|
+
sorted_entries.each do |entry|
|
48
|
+
menu.choice(render_entry(entry)) do
|
49
|
+
begin
|
50
|
+
entry.call_pre_hook
|
51
|
+
res = render_action(entry)
|
52
|
+
entry.call_post_hook
|
53
|
+
res
|
54
|
+
rescue KafoWizards::ValidationError => e
|
55
|
+
say ::HighLine.color("\nValidation error: #{e.message}", :red)
|
56
|
+
say "Please, try again... \n\n"
|
57
|
+
retry
|
58
|
+
rescue Interrupt
|
59
|
+
nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
def render_action(entry)
|
68
|
+
call_renderer_for_entry(:render_action, entry)
|
69
|
+
end
|
70
|
+
|
71
|
+
def render_value(entry)
|
72
|
+
call_renderer_for_entry(:render_value, entry)
|
73
|
+
end
|
74
|
+
|
75
|
+
def render_entry(entry)
|
76
|
+
call_renderer_for_entry(:render_entry, entry)
|
77
|
+
end
|
78
|
+
|
79
|
+
protected
|
80
|
+
def sorted_entries
|
81
|
+
sorted = { :default => [], :entries => [], :buttons => []}
|
82
|
+
sorted = entries.inject(sorted) do |res, entry|
|
83
|
+
if entry.class <= KafoWizards::Entries::ButtonEntry
|
84
|
+
cat = entry.default? ? :default : :buttons
|
85
|
+
else
|
86
|
+
cat = :entries
|
87
|
+
end
|
88
|
+
res[cat] << entry
|
89
|
+
res
|
90
|
+
end
|
91
|
+
sorted[:default] + sorted[:entries] + sorted[:buttons]
|
92
|
+
end
|
93
|
+
|
94
|
+
def format_errors(errors)
|
95
|
+
errors.map{ |e| "- #{e}"}.join("\n")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
metadata
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kafo_wizards
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Martin Bačovský
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-08-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: thor
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '4.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '4.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: simplecov
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: mocha
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: ci_reporter
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: highline
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: This gem helps to create wizard like interfaces in terminal applications,
|
126
|
+
has support for nesting and value validation
|
127
|
+
email:
|
128
|
+
- mbacovsk@redhat.com
|
129
|
+
executables: []
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- LICENSE.txt
|
134
|
+
- README.md
|
135
|
+
- Rakefile
|
136
|
+
- lib/kafo_wizards.rb
|
137
|
+
- lib/kafo_wizards/abstract_wizard.rb
|
138
|
+
- lib/kafo_wizards/entries.rb
|
139
|
+
- lib/kafo_wizards/entries/abstract.rb
|
140
|
+
- lib/kafo_wizards/entries/boolean.rb
|
141
|
+
- lib/kafo_wizards/entries/button.rb
|
142
|
+
- lib/kafo_wizards/entries/ip_address.rb
|
143
|
+
- lib/kafo_wizards/entries/netmask.rb
|
144
|
+
- lib/kafo_wizards/entries/password.rb
|
145
|
+
- lib/kafo_wizards/entries/selector.rb
|
146
|
+
- lib/kafo_wizards/entries/string.rb
|
147
|
+
- lib/kafo_wizards/entries/string_or_file.rb
|
148
|
+
- lib/kafo_wizards/exceptions.rb
|
149
|
+
- lib/kafo_wizards/factory.rb
|
150
|
+
- lib/kafo_wizards/highline.rb
|
151
|
+
- lib/kafo_wizards/highline/abstract_renderer.rb
|
152
|
+
- lib/kafo_wizards/highline/boolean_renderer.rb
|
153
|
+
- lib/kafo_wizards/highline/button_renderer.rb
|
154
|
+
- lib/kafo_wizards/highline/password_renderer.rb
|
155
|
+
- lib/kafo_wizards/highline/selector_renderer.rb
|
156
|
+
- lib/kafo_wizards/highline/string_or_file_renderer.rb
|
157
|
+
- lib/kafo_wizards/highline/string_renderer.rb
|
158
|
+
- lib/kafo_wizards/highline/wizard.rb
|
159
|
+
- lib/kafo_wizards/version.rb
|
160
|
+
homepage: https://github.com/theforeman/kafo_wizards
|
161
|
+
licenses:
|
162
|
+
- GPLv3+
|
163
|
+
metadata: {}
|
164
|
+
post_install_message:
|
165
|
+
rdoc_options: []
|
166
|
+
require_paths:
|
167
|
+
- lib
|
168
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - '>='
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '0'
|
173
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
174
|
+
requirements:
|
175
|
+
- - '>='
|
176
|
+
- !ruby/object:Gem::Version
|
177
|
+
version: '0'
|
178
|
+
requirements: []
|
179
|
+
rubyforge_project:
|
180
|
+
rubygems_version: 2.4.4
|
181
|
+
signing_key:
|
182
|
+
specification_version: 4
|
183
|
+
summary: Wizard like interfaces in terminal
|
184
|
+
test_files: []
|