royw-dvdprofiler2xbmc 0.0.6 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +0 -1
- data/History.txt +3 -0
- data/Manifest.txt +7 -1
- data/PostInstall.txt +31 -55
- data/README.rdoc +256 -60
- data/Rakefile +2 -1
- data/dvdprofiler2xbmc.gemspec +7 -4
- data/lib/dvdprofiler2xbmc.rb +1 -1
- data/lib/dvdprofiler2xbmc/app_config.rb +382 -52
- data/lib/dvdprofiler2xbmc/controllers/app.rb +79 -12
- data/lib/dvdprofiler2xbmc/controllers/fanart_controller.rb +40 -18
- data/lib/dvdprofiler2xbmc/controllers/nfo_controller.rb +51 -16
- data/lib/dvdprofiler2xbmc/controllers/thumbnail_controller.rb +2 -2
- data/lib/dvdprofiler2xbmc/models/collection.rb +3 -0
- data/lib/dvdprofiler2xbmc/models/dvdprofiler_profile.rb +9 -17
- data/lib/dvdprofiler2xbmc/models/imdb_profile.rb +2 -14
- data/lib/dvdprofiler2xbmc/models/media.rb +40 -21
- data/lib/dvdprofiler2xbmc/models/tmdb_profile.rb +1 -13
- data/lib/dvdprofiler2xbmc/models/xbmc_info.rb +2 -14
- data/lib/dvdprofiler2xbmc/views/cli.rb +25 -10
- data/lib/dvdprofiler2xbmc/views/config_editor.rb +289 -0
- data/spec/app_spec.rb +146 -0
- data/spec/config_editor_spec.rb +301 -0
- data/spec/dvdprofiler_profile_spec.rb +16 -1
- data/spec/fanart_controller_spec.rb +132 -0
- data/spec/media_spec.rb +86 -0
- data/spec/nfo_controller_spec.rb +12 -7
- data/spec/samples/Ma and Pa Kettle.cd1.dummy b/data/spec/samples/Ma and Pa → Kettle.cd1.dummy +0 -0
- data/spec/tmdb_profile_spec.rb +1 -0
- data/test/test_dvdprofiler2xbmc.rb +11 -0
- data/test/test_dvdprofiler2xbmc_cli.rb +14 -0
- data/test/test_helper.rb +3 -0
- metadata +20 -5
@@ -1,10 +1,8 @@
|
|
1
1
|
# == Synopsis
|
2
2
|
# Media encapsulates information about a single media file
|
3
3
|
class Media
|
4
|
-
attr_reader :media_path, :image_files, :fanart_files, :
|
5
|
-
attr_accessor :isbn, :imdb_id
|
6
|
-
|
7
|
-
DISC_NUMBER_REGEX = /\.(cd|part|disk|disc)\d+/i
|
4
|
+
attr_reader :media_path, :image_files, :fanart_files, :media_subdirs, :title, :title_with_year, :part, :extension
|
5
|
+
attr_accessor :isbn, :imdb_id, :resolution, :year
|
8
6
|
|
9
7
|
def initialize(directory, media_file)
|
10
8
|
@media_subdirs = File.dirname(media_file)
|
@@ -12,13 +10,19 @@ class Media
|
|
12
10
|
|
13
11
|
cwd = File.expand_path(Dir.getwd)
|
14
12
|
Dir.chdir(File.dirname(@media_path))
|
15
|
-
@nfo_files = Dir.glob("*.{#{AppConfig[:
|
16
|
-
@image_files = Dir.glob("*.{#{AppConfig[:
|
17
|
-
@fanart_files = Dir.glob("
|
13
|
+
@nfo_files = Dir.glob("*.{#{AppConfig[:extensions][:nfo]}}")
|
14
|
+
@image_files = Dir.glob("*.{#{AppConfig[:extensions][:thumbnail]}}")
|
15
|
+
@fanart_files = Dir.glob("*#{AppConfig[:extensions][:fanart]}*}")
|
18
16
|
Dir.chdir(cwd)
|
19
17
|
|
20
|
-
|
21
|
-
|
18
|
+
components = Media.parse(@media_path)
|
19
|
+
unless components.nil?
|
20
|
+
@year = components[:year]
|
21
|
+
@title = components[:title]
|
22
|
+
@part = components[:part]
|
23
|
+
@extension = components[:extension]
|
24
|
+
@resolution = components[:resolution]
|
25
|
+
end
|
22
26
|
@title_with_year = find_title_with_year(@title, @year)
|
23
27
|
end
|
24
28
|
|
@@ -32,11 +36,33 @@ class Media
|
|
32
36
|
# path_to('nfo') => '/a/b/c.nfo'
|
33
37
|
def path_to(type)
|
34
38
|
# ditch all extensions (ex, a.b => a, a.cd1.b => a)
|
35
|
-
|
36
|
-
|
37
|
-
|
39
|
+
DvdProfiler2Xbmc.generate_filespec(@media_path, type, :year => @year, :resolution => @resolution)
|
40
|
+
end
|
41
|
+
|
42
|
+
# parse the given filespec into a hash the consists of the
|
43
|
+
# found parts with keys:
|
44
|
+
# :title required
|
45
|
+
# :year optional
|
46
|
+
# :part optional
|
47
|
+
# :extension required
|
48
|
+
def self.parse(filespec)
|
49
|
+
result = nil
|
50
|
+
filename = File.basename(filespec)
|
51
|
+
AppConfig[:media_parsers].each do |parser|
|
52
|
+
match_data = parser.regex.match(filename)
|
53
|
+
unless match_data.nil?
|
54
|
+
if((match_data.length - 1) == parser.tokens.length)
|
55
|
+
index = 1
|
56
|
+
result = {}
|
57
|
+
parser.tokens.each do |token|
|
58
|
+
result[token] = match_data[index]
|
59
|
+
index += 1
|
60
|
+
end
|
61
|
+
break
|
62
|
+
end
|
63
|
+
end
|
38
64
|
end
|
39
|
-
|
65
|
+
result
|
40
66
|
end
|
41
67
|
|
42
68
|
def to_s
|
@@ -51,14 +77,7 @@ class Media
|
|
51
77
|
|
52
78
|
# return the media's title extracted from the filename and cleaned up
|
53
79
|
def find_title(media_path)
|
54
|
-
|
55
|
-
title = File.basename(media_path, ".*").gsub(DISC_NUMBER_REGEX, '')
|
56
|
-
title.gsub!(/\s\-\s\d{4}/, '') # remove year
|
57
|
-
title.gsub!(/\s\-\s0/, '') # remove "- 0", i.e., bad year
|
58
|
-
title.gsub!(/\(\d{4}\)/, '') # remove (year)
|
59
|
-
title.gsub!(/\[.+\]/, '') # remove square brackets
|
60
|
-
title.gsub!(/\s\s+/, ' ') # remove multiple whitespace
|
61
|
-
title.strip # remove leading and trailing whitespace
|
80
|
+
Media.parse(media_path)[:title] rescue nil
|
62
81
|
end
|
63
82
|
|
64
83
|
# return the media's title but with the (year) appended
|
@@ -90,23 +90,11 @@ class TmdbProfile
|
|
90
90
|
xml = self.to_xml
|
91
91
|
unless xml.blank?
|
92
92
|
AppConfig[:logger].debug { "saving #{filespec}" }
|
93
|
-
save_to_file(filespec, xml)
|
93
|
+
DvdProfiler2Xbmc.save_to_file(filespec, xml)
|
94
94
|
end
|
95
95
|
rescue Exception => e
|
96
96
|
AppConfig[:logger].error "Unable to save tmdb profile to #{filespec} - #{e.to_s}"
|
97
97
|
end
|
98
98
|
end
|
99
99
|
|
100
|
-
def save_to_file(filespec, data)
|
101
|
-
new_filespec = filespec + AppConfig[:new_extension]
|
102
|
-
File.open(new_filespec, "w") do |file|
|
103
|
-
file.puts(data)
|
104
|
-
end
|
105
|
-
backup_filespec = filespec + AppConfig[:backup_extension]
|
106
|
-
File.delete(backup_filespec) if File.exist?(backup_filespec)
|
107
|
-
File.rename(filespec, backup_filespec) if File.exist?(filespec)
|
108
|
-
File.rename(new_filespec, filespec)
|
109
|
-
File.delete(new_filespec) if File.exist?(new_filespec)
|
110
|
-
end
|
111
|
-
|
112
100
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
#
|
4
4
|
# Usage:
|
5
5
|
#
|
6
|
-
# profile = XbmcInfo.new(media.path_to(:
|
6
|
+
# profile = XbmcInfo.new(media.path_to(:nfo))
|
7
7
|
#
|
8
8
|
# profile.movie['key'] = 'some value'
|
9
9
|
# puts profile.movie['key']
|
@@ -58,7 +58,7 @@ class XbmcInfo
|
|
58
58
|
xml = self.to_xml
|
59
59
|
unless xml.blank?
|
60
60
|
AppConfig[:logger].info { "updated #{@nfo_filespec}"}
|
61
|
-
save_to_file(@nfo_filespec, xml)
|
61
|
+
DvdProfiler2Xbmc.save_to_file(@nfo_filespec, xml)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
rescue Exception => e
|
@@ -83,18 +83,6 @@ class XbmcInfo
|
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
|
-
def save_to_file(filespec, data)
|
87
|
-
new_filespec = filespec + AppConfig[:new_extension]
|
88
|
-
File.open(new_filespec, "w") do |file|
|
89
|
-
file.puts(data)
|
90
|
-
end
|
91
|
-
backup_filespec = filespec + AppConfig[:backup_extension]
|
92
|
-
File.delete(backup_filespec) if File.exist?(backup_filespec)
|
93
|
-
File.rename(filespec, backup_filespec) if File.exist?(filespec)
|
94
|
-
File.rename(new_filespec, filespec)
|
95
|
-
File.delete(new_filespec) if File.exist?(new_filespec)
|
96
|
-
end
|
97
|
-
|
98
86
|
# has any of the data changed?
|
99
87
|
def dirty?
|
100
88
|
result = false
|
@@ -1,5 +1,6 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'config_editor')
|
1
2
|
require 'commandline/optionparser'
|
2
|
-
include CommandLine
|
3
|
+
# include CommandLine
|
3
4
|
|
4
5
|
# Command Line interface for the Dvdprofiler2Xbmc application.
|
5
6
|
# All application output is via AppConfig[:logger] so we have
|
@@ -36,10 +37,21 @@ module Dvdprofiler2xbmc
|
|
36
37
|
# parse the command line
|
37
38
|
options = setup_parser()
|
38
39
|
od = options.parse(arguments)
|
40
|
+
run_editor = !AppConfig.exist?
|
39
41
|
|
40
42
|
setup_app_config(od, logger)
|
43
|
+
run_editor = true unless AppConfig.valid?
|
41
44
|
|
42
|
-
|
45
|
+
logger.info(AppConfig.to_s) if od["--show_config"]
|
46
|
+
|
47
|
+
if run_editor || od["--edit_config"]
|
48
|
+
editor = ConfigEditor.new
|
49
|
+
editor.execute
|
50
|
+
end
|
51
|
+
|
52
|
+
skip_execution = false
|
53
|
+
%w(--help --version --show_config --edit_config).each {|flag| skip_execution = true if od[flag] || run_editor}
|
54
|
+
unless skip_execution
|
43
55
|
# create and execute class instance here
|
44
56
|
app = DvdProfiler2Xbmc.instance
|
45
57
|
app.execute
|
@@ -65,7 +77,6 @@ module Dvdprofiler2xbmc
|
|
65
77
|
reinitialize_logger(logger, od["--quiet"], od["--debug"])
|
66
78
|
AppConfig.load
|
67
79
|
AppConfig.save
|
68
|
-
AppConfig[:imdb_query] = !od["--no_imdb_query"]
|
69
80
|
AppConfig[:logfile] = od['--output'] if od['--output']
|
70
81
|
AppConfig[:logfile_level] = od['--output_level'] if od['--output_level']
|
71
82
|
reinitialize_logger(logger, od["--quiet"], od["--debug"])
|
@@ -80,7 +91,7 @@ module Dvdprofiler2xbmc
|
|
80
91
|
# Setup the command line option parser
|
81
92
|
# Returns:: OptionParser instances
|
82
93
|
def self.setup_parser()
|
83
|
-
options = OptionParser.new()
|
94
|
+
options = CommandLine::OptionParser.new()
|
84
95
|
|
85
96
|
# flag options
|
86
97
|
[
|
@@ -95,8 +106,12 @@ module Dvdprofiler2xbmc
|
|
95
106
|
:opt_description => "This usage information"
|
96
107
|
},
|
97
108
|
{
|
98
|
-
:names => %w(--
|
99
|
-
:opt_description =>
|
109
|
+
:names => %w(--show_config -s),
|
110
|
+
:opt_description => "This is the current configuration information"
|
111
|
+
},
|
112
|
+
{
|
113
|
+
:names => %w(--edit_config -e),
|
114
|
+
:opt_description => "Edit the current configuration information"
|
100
115
|
},
|
101
116
|
{
|
102
117
|
:names => %w(--quiet -q),
|
@@ -114,7 +129,7 @@ module Dvdprofiler2xbmc
|
|
114
129
|
:names => %w(--reports -r),
|
115
130
|
:opt_description => 'Display reports only. Do not do any updates.'
|
116
131
|
}
|
117
|
-
].each { |opt| options << Option.new(:flag, opt) }
|
132
|
+
].each { |opt| options << CommandLine::Option.new(:flag, opt) }
|
118
133
|
|
119
134
|
# non-flag options
|
120
135
|
[
|
@@ -123,16 +138,16 @@ module Dvdprofiler2xbmc
|
|
123
138
|
:argument_arity => [1,1],
|
124
139
|
:arg_description => 'logfile',
|
125
140
|
:opt_description => 'Write log messages to file. Default = no log file',
|
126
|
-
:opt_found => OptionParser::GET_ARGS
|
141
|
+
:opt_found => CommandLine::OptionParser::GET_ARGS
|
127
142
|
},
|
128
143
|
{
|
129
144
|
:names => %w(--output_level -l),
|
130
145
|
:argument_arity => [1,1],
|
131
146
|
:arg_description => 'level',
|
132
147
|
:opt_description => 'Output logging level: DEBUG, INFO, WARN, ERROR. Default = INFO',
|
133
|
-
:opt_found => OptionParser::GET_ARGS
|
148
|
+
:opt_found => CommandLine::OptionParser::GET_ARGS
|
134
149
|
}
|
135
|
-
].each { |opt| options << Option.new(opt) }
|
150
|
+
].each { |opt| options << CommandLine::Option.new(opt) }
|
136
151
|
|
137
152
|
options
|
138
153
|
end
|
@@ -0,0 +1,289 @@
|
|
1
|
+
# require 'highline'
|
2
|
+
require "highline/import"
|
3
|
+
|
4
|
+
# monkey patch HighLine to get rid of the ugly message:
|
5
|
+
# Your answer isn't valid (must match #<Proc:0xb76cb378@/home/royw/views/dvdprofiler2xbmc/lib/dvdprofiler2xbmc/app_config.rb:180>)
|
6
|
+
# basically the problem is with inspecting a lambda validator, so just don't do it...
|
7
|
+
class HighLine
|
8
|
+
class Question
|
9
|
+
def build_responses( )
|
10
|
+
append_default unless default.nil?
|
11
|
+
@responses = { :ambiguous_completion =>
|
12
|
+
"Ambiguous choice. " +
|
13
|
+
"Please choose one of #{@answer_type.inspect}.",
|
14
|
+
:ask_on_error =>
|
15
|
+
"? ",
|
16
|
+
:invalid_type =>
|
17
|
+
"You must enter a valid #{@answer_type}.",
|
18
|
+
:no_completion =>
|
19
|
+
"You must choose one of " +
|
20
|
+
"#{@answer_type.inspect}.",
|
21
|
+
:not_in_range =>
|
22
|
+
"Your answer isn't within the expected range " +
|
23
|
+
"(#{expected_range}).",
|
24
|
+
:not_valid =>
|
25
|
+
"Your answer isn't valid " +
|
26
|
+
(@validate.kind_of?(Proc) ?
|
27
|
+
'' : "(must match #{@validate.inspect}).")
|
28
|
+
}.merge(@responses)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class ConfigEditor
|
34
|
+
|
35
|
+
def initialize
|
36
|
+
end
|
37
|
+
|
38
|
+
def execute
|
39
|
+
@saved_interrupt_message = DvdProfiler2Xbmc.interrupt_message
|
40
|
+
DvdProfiler2Xbmc.interrupt_message = ''
|
41
|
+
report_invalid_config_items
|
42
|
+
begin
|
43
|
+
AppConfig[:logger].info('Configuration Editor')
|
44
|
+
|
45
|
+
fields = AppConfig.navigation.collect do |page|
|
46
|
+
page.values.flatten.select do|field|
|
47
|
+
AppConfig.data_type[field]
|
48
|
+
end
|
49
|
+
end.flatten.uniq.compact
|
50
|
+
while(field = menu_select('field', fields))
|
51
|
+
begin
|
52
|
+
edit_field(field)
|
53
|
+
rescue
|
54
|
+
end
|
55
|
+
end
|
56
|
+
if agree("Save? yes/no") {|q| q.default = 'yes'}
|
57
|
+
AppConfig.save
|
58
|
+
end
|
59
|
+
rescue
|
60
|
+
end
|
61
|
+
DvdProfiler2Xbmc.interrupt_message = @saved_interrupt_message
|
62
|
+
end
|
63
|
+
|
64
|
+
def report_invalid_config_items
|
65
|
+
buf = []
|
66
|
+
AppConfig.validate.each do |field, value|
|
67
|
+
unless AppConfig.validate[field].call(AppConfig.config[field])
|
68
|
+
buf << field
|
69
|
+
end
|
70
|
+
end
|
71
|
+
unless buf.empty?
|
72
|
+
say 'The following config items are not valid and need to be changed:'
|
73
|
+
buf.each {|line| say " #{line}"}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def edit_field(field)
|
78
|
+
result = true
|
79
|
+
while(result)
|
80
|
+
field_header(field)
|
81
|
+
|
82
|
+
choose do |menu|
|
83
|
+
menu.prompt = "Please select: "
|
84
|
+
menu.index = :number
|
85
|
+
menu.index_suffix = ') '
|
86
|
+
menu.choice(:quit, 'Quit') {result = false}
|
87
|
+
case AppConfig.data_type[field]
|
88
|
+
when :BOOLEAN
|
89
|
+
menu.choice(:true, 'True') {AppConfig.config[field] = true}
|
90
|
+
menu.choice(:false, 'False') {AppConfig.config[field] = false}
|
91
|
+
else
|
92
|
+
menu.choice(:default, 'Default') {AppConfig.config[field] = AppConfig.initial[field]}
|
93
|
+
if AppConfig.data_type[field].to_s =~ /^ARRAY/
|
94
|
+
menu.choice(:add, 'Add') {array_add(field)}
|
95
|
+
menu.choice(:delete, 'Delete') {array_delete(field)}
|
96
|
+
elsif AppConfig.data_type[field].to_s =~ /^HASH/
|
97
|
+
menu.choice(:add, 'Add') {hash_add(field)}
|
98
|
+
menu.choice(:delete, 'Delete') {hash_delete(field)}
|
99
|
+
else
|
100
|
+
menu.choice(:edit, 'Edit') {object_edit(field)}
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
result
|
106
|
+
end
|
107
|
+
|
108
|
+
def field_header(field)
|
109
|
+
say "\n"
|
110
|
+
say "-------------------------------"
|
111
|
+
say field
|
112
|
+
say "\n"
|
113
|
+
say AppConfig.help[field]
|
114
|
+
say "\n"
|
115
|
+
say "Default:"
|
116
|
+
say prettify(AppConfig.initial[field])
|
117
|
+
say "\n"
|
118
|
+
say "Current:"
|
119
|
+
say prettify(AppConfig.config[field])
|
120
|
+
say "\n"
|
121
|
+
end
|
122
|
+
|
123
|
+
def object_edit(field)
|
124
|
+
value = data_type_editor(field, AppConfig.data_type[field], AppConfig.initial[field])
|
125
|
+
AppConfig.config[field] = value unless value.nil?
|
126
|
+
end
|
127
|
+
|
128
|
+
def hash_add(field)
|
129
|
+
value = data_type_editor(field, AppConfig.data_type[field], AppConfig.initial[field])
|
130
|
+
if value =~ /([^,]+)\s*,\s*(\S.*)/
|
131
|
+
AppConfig.config[field][$1.strip] = $2.strip
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def hash_delete(field)
|
136
|
+
choose do |menu|
|
137
|
+
menu.prompt = "Please select to remove: "
|
138
|
+
menu.index = :number
|
139
|
+
menu.index_suffix = ') '
|
140
|
+
menu.choice(:quit, 'Quit') {result = false}
|
141
|
+
values = []
|
142
|
+
AppConfig.config[field].each do |key, value|
|
143
|
+
values << "#{key} => #{value}"
|
144
|
+
end
|
145
|
+
menu.choices(*values) do |value, details|
|
146
|
+
if value =~ /(.*\S)\s+=>/
|
147
|
+
AppConfig.config[field].delete($1)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def array_add(field)
|
154
|
+
value = data_type_editor(field, AppConfig.data_type[field], AppConfig.initial[field])
|
155
|
+
AppConfig.config[field] += [value].flatten unless value.nil?
|
156
|
+
AppConfig.config[field].uniq!
|
157
|
+
end
|
158
|
+
|
159
|
+
def array_delete(field)
|
160
|
+
choose do |menu|
|
161
|
+
menu.prompt = "Please select to remove: "
|
162
|
+
menu.index = :number
|
163
|
+
menu.index_suffix = ') '
|
164
|
+
menu.choice(:quit, 'Quit') {result = false}
|
165
|
+
menu.choices(*AppConfig.config[field]) do |extension, details|
|
166
|
+
AppConfig.config[field].delete(extension)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def prettify(obj)
|
172
|
+
str = obj.pretty_inspect
|
173
|
+
if obj.kind_of? Mash
|
174
|
+
str = obj.to_hash.pretty_inspect
|
175
|
+
end
|
176
|
+
if obj.kind_of? Array
|
177
|
+
str = obj.inspect
|
178
|
+
end
|
179
|
+
if obj.kind_of? Hash
|
180
|
+
key_length = 0
|
181
|
+
obj.keys.each do |key|
|
182
|
+
key_length = key.length if key.length > key_length
|
183
|
+
end
|
184
|
+
buf = []
|
185
|
+
obj.each do |key,value|
|
186
|
+
buf << sprintf("%-#{key_length}.#{key_length}s => %s", key, value)
|
187
|
+
end
|
188
|
+
str = buf.join("\n")
|
189
|
+
end
|
190
|
+
str
|
191
|
+
end
|
192
|
+
|
193
|
+
def data_type_editor(field, data_type, default_value=nil)
|
194
|
+
value = nil
|
195
|
+
case data_type
|
196
|
+
when :BOOLEAN
|
197
|
+
value = agree("Set #{field} to true: ") do |q|
|
198
|
+
q.default = (default_value ? 'yes' : 'no') unless default_value.nil?
|
199
|
+
end
|
200
|
+
when :FILESPEC
|
201
|
+
value = ask('New filespec: ') do |q|
|
202
|
+
# q.answer_type = File
|
203
|
+
q.validate = AppConfig.validate_item[field] unless AppConfig.validate_item[field].nil?
|
204
|
+
q.confirm = false
|
205
|
+
q.default = default_value unless default_value.nil?
|
206
|
+
end
|
207
|
+
when :PATHSPEC
|
208
|
+
value = ask('New pathspec: ') do |q|
|
209
|
+
# q.answer_type = Pathname
|
210
|
+
# q.validate = lambda { |v| File.exist?(v) && File.directory?(v) }
|
211
|
+
q.validate = AppConfig.validate_item[field] unless AppConfig.validate_item[field].nil?
|
212
|
+
q.confirm = false
|
213
|
+
q.default = default_value unless default_value.nil?
|
214
|
+
end
|
215
|
+
when :PERMISSIONS
|
216
|
+
value = ask('New value (octal): ') do |q|
|
217
|
+
# q.validate = lambda { |v| (v.to_i(8) >= 0) && (v.to_i(8) <= 07777) }
|
218
|
+
q.validate = AppConfig.validate_item[field] unless AppConfig.validate_item[field].nil?
|
219
|
+
q.default = default_value unless default_value.nil?
|
220
|
+
end
|
221
|
+
when :ARRAY_OF_STRINGS
|
222
|
+
value = ask('New values or a blank line to quit: ') do |q|
|
223
|
+
q.gather = ''
|
224
|
+
q.validate = AppConfig.validate_item[field] unless AppConfig.validate_item[field].nil?
|
225
|
+
# note, can not have both gather and default as there is no way to
|
226
|
+
# terminate the input loop
|
227
|
+
end
|
228
|
+
when :ARRAY_OF_PATHSPECS
|
229
|
+
# note, can not have both gather and default as there is no way to
|
230
|
+
# terminate the input loop
|
231
|
+
value = ask('New pathspecs or a blank line to quit: ') do |q|
|
232
|
+
q.gather = ''
|
233
|
+
# q.validate = lambda { |v| v.empty? || (File.exist?(v) && File.directory?(v)) }
|
234
|
+
q.validate = AppConfig.validate_item[field] unless AppConfig.validate_item[field].nil?
|
235
|
+
end
|
236
|
+
when :HASH_FIXED_SYMBOL_KEYS_STRING_VALUES
|
237
|
+
when :HASH_STRING_KEYS_STRING_VALUES
|
238
|
+
value = ask('New value as key,value: ') do |q|
|
239
|
+
# q.default = default_value unless default_value.nil?
|
240
|
+
end
|
241
|
+
else
|
242
|
+
value = ask('New value: ')
|
243
|
+
end
|
244
|
+
value
|
245
|
+
end
|
246
|
+
|
247
|
+
VALUE_LENGTH = 60
|
248
|
+
|
249
|
+
def menu_select(name, values)
|
250
|
+
result = false
|
251
|
+
say("\n#{name.capitalize} Selection")
|
252
|
+
choose do |menu|
|
253
|
+
menu.prompt = "Please select #{name}: "
|
254
|
+
menu.index = :number
|
255
|
+
menu.index_suffix = ') '
|
256
|
+
menu.choice(:quit, 'Quit') {result = false}
|
257
|
+
menu.choices(*(values.collect{|v| field_name_choice(v)})) do |command, details|
|
258
|
+
result = command.split(" ").first
|
259
|
+
end
|
260
|
+
end
|
261
|
+
result
|
262
|
+
end
|
263
|
+
|
264
|
+
def field_name_choice(value)
|
265
|
+
value_str = sprintf("%-#{VALUE_LENGTH}.#{VALUE_LENGTH}s", first_line(value))
|
266
|
+
if AppConfig.config[:color_enabled]
|
267
|
+
color = 'green'
|
268
|
+
unless AppConfig.validate[value].nil?
|
269
|
+
color = 'red' unless AppConfig.validate[value].call(AppConfig.config[value])
|
270
|
+
end
|
271
|
+
value_str = "<%= color('#{value_str}', :#{color})%>"
|
272
|
+
end
|
273
|
+
str = sprintf("%20s %s", value, value_str)
|
274
|
+
str
|
275
|
+
end
|
276
|
+
|
277
|
+
def first_line(value)
|
278
|
+
config_value = AppConfig.config[value]
|
279
|
+
if config_value.kind_of? Mash
|
280
|
+
config_value = config_value.to_hash
|
281
|
+
end
|
282
|
+
str = [config_value.inspect].flatten.first.split("\n").first
|
283
|
+
if str.length > VALUE_LENGTH
|
284
|
+
str = str[0..(VALUE_LENGTH - 4)] + '...'
|
285
|
+
end
|
286
|
+
str
|
287
|
+
end
|
288
|
+
|
289
|
+
end
|