everyday-cli-utils 1.8.2 → 1.8.3
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 +4 -4
- data/.gitignore +0 -1
- data/Gemfile +1 -0
- data/Gemfile.ci +2 -1
- data/Gemfile.lock +45 -0
- data/README.md +5 -8
- data/everyday-cli-utils.gemspec +3 -3
- data/lib/everyday-cli-utils/ask.rb +5 -0
- data/lib/everyday-cli-utils/option.rb +166 -113
- data/lib/everyday-cli-utils/override.rb +38 -26
- data/lib/everyday-cli-utils/version.rb +1 -1
- data/spec/everyday-cli-utils/maputil_spec.rb +6 -6
- data/spec/everyday-cli-utils/option_spec.rb +1 -1
- data/spec/everyday-cli-utils/override_spec.rb +1 -1
- data/spec/spec_helper.rb +2 -0
- metadata +13 -11
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7892604af4bb9b58227dea18a0c14a9c8daaffb9
|
|
4
|
+
data.tar.gz: b0dfde2c8a940aeb9f09104f27b523f0a8867a5b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 65770fbd4440a17dfafd6d5b4234aad239de0ee499f5c7be24e8f1ed3589d02f190f80fdb3e4822c9887371194ae3acf7c17d58148fcefac67a01b6c02e8dddf
|
|
7
|
+
data.tar.gz: 83ad2e2ad25d0fd7cfe1efdeb9fba19a71215f2ee27372cce584da79f51e7bb6b18c993bfcd2352d60a5482f5d6475c15b7a7a2b50c95e6648fb6cd798dca36a
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/Gemfile.ci
CHANGED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
everyday-cli-utils (1.8.2)
|
|
5
|
+
|
|
6
|
+
GEM
|
|
7
|
+
remote: https://rubygems.org/
|
|
8
|
+
specs:
|
|
9
|
+
codeclimate-test-reporter (0.4.7)
|
|
10
|
+
simplecov (>= 0.7.1, < 1.0.0)
|
|
11
|
+
diff-lcs (1.2.5)
|
|
12
|
+
docile (1.1.5)
|
|
13
|
+
json (1.8.3)
|
|
14
|
+
rake (10.4.2)
|
|
15
|
+
rspec (3.3.0)
|
|
16
|
+
rspec-core (~> 3.3.0)
|
|
17
|
+
rspec-expectations (~> 3.3.0)
|
|
18
|
+
rspec-mocks (~> 3.3.0)
|
|
19
|
+
rspec-core (3.3.1)
|
|
20
|
+
rspec-support (~> 3.3.0)
|
|
21
|
+
rspec-expectations (3.3.0)
|
|
22
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
23
|
+
rspec-support (~> 3.3.0)
|
|
24
|
+
rspec-mocks (3.3.1)
|
|
25
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
26
|
+
rspec-support (~> 3.3.0)
|
|
27
|
+
rspec-support (3.3.0)
|
|
28
|
+
simplecov (0.10.0)
|
|
29
|
+
docile (~> 1.1.0)
|
|
30
|
+
json (~> 1.8)
|
|
31
|
+
simplecov-html (~> 0.10.0)
|
|
32
|
+
simplecov-html (0.10.0)
|
|
33
|
+
|
|
34
|
+
PLATFORMS
|
|
35
|
+
ruby
|
|
36
|
+
|
|
37
|
+
DEPENDENCIES
|
|
38
|
+
bundler (~> 1.10)
|
|
39
|
+
codeclimate-test-reporter (~> 0.4, >= 0.4.7)
|
|
40
|
+
everyday-cli-utils!
|
|
41
|
+
rake (~> 10.4)
|
|
42
|
+
rspec (~> 3.3)
|
|
43
|
+
|
|
44
|
+
BUNDLED WITH
|
|
45
|
+
1.10.4
|
data/README.md
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
# EverydayCliUtils
|
|
2
2
|
|
|
3
|
-
[](http://badge.fury.io/rb/everyday-cli-utils)
|
|
4
|
+
[](https://travis-ci.org/henderea/everyday-cli-utils)
|
|
5
|
+
[](https://gemnasium.com/henderea/everyday-cli-utils)
|
|
6
|
+
[](https://codeclimate.com/github/henderea/everyday-cli-utils)
|
|
7
|
+
[](https://codeclimate.com/github/henderea/everyday-cli-utils)
|
|
8
8
|
|
|
9
9
|
A few CLI and general utilities. Includes a numbered-menu select loop utility, a ANSI formatting escape code handler, a text-based histogram maker, k-means and n-means (k-means with minimum optimal k) calculators, various collection utility methods, and a utility for using OptionParser with less code.
|
|
10
10
|
|
|
11
11
|
Note: The curses utility has been moved to the `everyday-curses` gem
|
|
12
12
|
|
|
13
|
-
## Issue Tracking
|
|
14
|
-
Please use <https://everydayprogramminggenius.atlassian.net/browse/ECU> for issue tracking.
|
|
15
|
-
|
|
16
13
|
## Installation
|
|
17
14
|
|
|
18
15
|
Add this line to your application's Gemfile:
|
data/everyday-cli-utils.gemspec
CHANGED
|
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
|
|
|
20
20
|
|
|
21
21
|
spec.required_ruby_version = '>= 1.9.3'
|
|
22
22
|
|
|
23
|
-
spec.add_development_dependency 'bundler', '~> 1.
|
|
24
|
-
spec.add_development_dependency 'rake', '~> 10.
|
|
25
|
-
spec.add_development_dependency 'rspec'
|
|
23
|
+
spec.add_development_dependency 'bundler', '~> 1.10'
|
|
24
|
+
spec.add_development_dependency 'rake', '~> 10.4'
|
|
25
|
+
spec.add_development_dependency 'rspec', '~> 3.3'
|
|
26
26
|
end
|
|
@@ -23,6 +23,11 @@ module EverydayCliUtils
|
|
|
23
23
|
block.call(options[val.to_i - 1])
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
def self::ask_yn(question, &block)
|
|
27
|
+
resp = Readline.readline("#{question} (yes/no) ", true)
|
|
28
|
+
block.call(resp.downcase == 'yes' || resp.downcase == 'y')
|
|
29
|
+
end
|
|
30
|
+
|
|
26
31
|
def self::hash_to_options(hash, extra = [])
|
|
27
32
|
hash.keys + extra
|
|
28
33
|
end
|
|
@@ -4,22 +4,24 @@ require 'yaml'
|
|
|
4
4
|
|
|
5
5
|
module EverydayCliUtils
|
|
6
6
|
class Option
|
|
7
|
-
|
|
8
|
-
opts
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
class << self
|
|
8
|
+
def add_option(options, opts, names, opt_name, settings = {})
|
|
9
|
+
opts.on(*names) {
|
|
10
|
+
options[opt_name] = !settings[:toggle] || !options[opt_name]
|
|
11
|
+
yield if block_given?
|
|
12
|
+
}
|
|
13
|
+
end
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
def add_option_with_param(options, opts, names, opt_name, settings = {})
|
|
16
|
+
opts.on(*names, settings[:type] || String) { |param|
|
|
17
|
+
if settings[:append]
|
|
18
|
+
options[opt_name] << param
|
|
19
|
+
else
|
|
20
|
+
options[opt_name] = param
|
|
21
|
+
end
|
|
22
|
+
yield if block_given?
|
|
23
|
+
}
|
|
24
|
+
end
|
|
23
25
|
end
|
|
24
26
|
end
|
|
25
27
|
|
|
@@ -46,54 +48,86 @@ module EverydayCliUtils
|
|
|
46
48
|
end
|
|
47
49
|
|
|
48
50
|
class OptionTypes
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
51
|
+
class << self
|
|
52
|
+
def def_type(type, default_value_block, value_determine_block, name_mod_block = nil, value_transform_block = nil)
|
|
53
|
+
@types ||= {}
|
|
54
|
+
@types[type] = OptionType.new(default_value_block, value_determine_block, name_mod_block, value_transform_block)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def default_value(type, settings = {})
|
|
58
|
+
@types ||= {}
|
|
59
|
+
@types.has_key?(type) ? @types[type].default_value(settings) : nil
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def updated_value(type, current_value, new_value, settings = {})
|
|
63
|
+
@types ||= {}
|
|
64
|
+
@types.has_key?(type) ? @types[type].updated_value(current_value, new_value, settings) : current_value
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def mod_names(type, names, settings = {})
|
|
68
|
+
@types ||= {}
|
|
69
|
+
@types.has_key?(type) ? @types[type].mod_names(names, settings) : names
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
#region option procs
|
|
73
|
+
def option_default(_)
|
|
74
|
+
false
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def option_value_determine(current_value, new_value, settings)
|
|
78
|
+
new_value ? (!settings[:toggle] || !current_value) : current_value
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def option_name_mod(names, settings)
|
|
82
|
+
settings.has_key?(:desc) ? (names + [settings[:desc]]) : names
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def option_value_transform(new_value, _)
|
|
86
|
+
!(!new_value)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
#endregion
|
|
90
|
+
|
|
91
|
+
def def_option_type
|
|
92
|
+
def_type(:option,
|
|
93
|
+
method(:option_default),
|
|
94
|
+
method(:option_value_determine),
|
|
95
|
+
method(:option_name_mod),
|
|
96
|
+
method(:option_value_transform))
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
#region option_with_param procs
|
|
100
|
+
def param_option_default(settings)
|
|
101
|
+
settings[:append] ? [] : nil
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def param_option_value_determine(current_value, new_value, settings)
|
|
105
|
+
settings[:append] ? (current_value + new_value) : ((new_value.nil? || new_value == '') ? current_value : new_value)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def param_option_name_mod(names, settings)
|
|
109
|
+
names[0] << ' PARAM' unless names.any? { |v| v.include?(' ') }
|
|
110
|
+
names = settings.has_key?(:desc) ? (names + [settings[:desc]]) : names
|
|
111
|
+
settings.has_key?(:type) ? (names + [settings[:type]]) : names
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def param_option_value_transform(new_value, settings)
|
|
115
|
+
new_value.is_a?(Array) ? (settings[:append] ? new_value : new_value[0]) : (settings[:append] ? [new_value] : new_value)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
#endregion
|
|
119
|
+
|
|
120
|
+
def def_option_with_param_type
|
|
121
|
+
def_type(:option_with_param,
|
|
122
|
+
method(:param_option_default),
|
|
123
|
+
method(:param_option_value_determine),
|
|
124
|
+
method(:param_option_name_mod),
|
|
125
|
+
method(:param_option_value_transform))
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def_option_type
|
|
130
|
+
def_option_with_param_type
|
|
97
131
|
end
|
|
98
132
|
|
|
99
133
|
class OptionDef
|
|
@@ -128,15 +162,17 @@ module EverydayCliUtils
|
|
|
128
162
|
value
|
|
129
163
|
end
|
|
130
164
|
|
|
131
|
-
|
|
132
|
-
settings
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
165
|
+
class << self
|
|
166
|
+
def register(opts, options, type, opt_name, names, settings = {}, default_settings = {}, &block)
|
|
167
|
+
settings = EverydayCliUtils::MapUtil.extend_hash(default_settings, settings)
|
|
168
|
+
opt = OptionDef.new(type, names.clone, settings, &block)
|
|
169
|
+
options[opt_name] = opt
|
|
170
|
+
names = OptionTypes.mod_names(type, names, settings)
|
|
171
|
+
opts.on(*names) { |*args|
|
|
172
|
+
opt.update(args, :arg)
|
|
173
|
+
opt.run
|
|
174
|
+
}
|
|
175
|
+
end
|
|
140
176
|
end
|
|
141
177
|
end
|
|
142
178
|
|
|
@@ -169,12 +205,14 @@ module EverydayCliUtils
|
|
|
169
205
|
@pre_parse_block.call(self, options_list) unless @pre_parse_block.nil?
|
|
170
206
|
end
|
|
171
207
|
|
|
172
|
-
|
|
173
|
-
settings
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
208
|
+
class << self
|
|
209
|
+
def register(order, opts, options, opt_name, names, exit_on_action, print_on_exit_str, settings, default_settings, action_block, pre_parse_block = nil)
|
|
210
|
+
settings = EverydayCliUtils::MapUtil.extend_hash(default_settings, settings)
|
|
211
|
+
opt = SpecialOptionDef.new(order, exit_on_action, names, print_on_exit_str, settings, action_block, pre_parse_block)
|
|
212
|
+
options.special_options[opt_name] = opt
|
|
213
|
+
names << settings[:desc] if settings.has_key?(:desc)
|
|
214
|
+
opts.on(*names) { opt.state = true }
|
|
215
|
+
end
|
|
178
216
|
end
|
|
179
217
|
end
|
|
180
218
|
|
|
@@ -219,11 +257,15 @@ module EverydayCliUtils
|
|
|
219
257
|
end
|
|
220
258
|
|
|
221
259
|
def run_special
|
|
222
|
-
|
|
260
|
+
run_special_helper { |v| v[1].run(self) }
|
|
223
261
|
end
|
|
224
262
|
|
|
225
263
|
def run_special_pre_parse
|
|
226
|
-
|
|
264
|
+
run_special_helper { |v| v[1].run_pre_parse(self) }
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def run_special_helper(&block)
|
|
268
|
+
@special_options.to_a.sort_by { |v| v[1].order }.each(&block)
|
|
227
269
|
end
|
|
228
270
|
|
|
229
271
|
def composite(*layers)
|
|
@@ -263,15 +305,17 @@ module EverydayCliUtils
|
|
|
263
305
|
def options_to_str(options, indent = 4)
|
|
264
306
|
str = ''
|
|
265
307
|
max_name_len = @options.values.map { |v| v.names.join(', ').length }.max
|
|
266
|
-
options.each { |v|
|
|
267
|
-
opt = @options[v[0]]
|
|
268
|
-
val = v[1]
|
|
269
|
-
names_str = opt.names.join(', ')
|
|
270
|
-
str << "#{' ' * indent}#{names_str}#{' ' * ((max_name_len + 4) - names_str.length)}#{val_to_str(val)}\n"
|
|
271
|
-
}
|
|
308
|
+
options.each { |v| str << build_option_str(v, indent, max_name_len) }
|
|
272
309
|
str
|
|
273
310
|
end
|
|
274
311
|
|
|
312
|
+
def build_option_str(v, indent, max_name_len)
|
|
313
|
+
opt = @options[v[0]]
|
|
314
|
+
val = v[1]
|
|
315
|
+
names_str = opt.names.join(', ')
|
|
316
|
+
"#{' ' * indent}#{names_str}#{' ' * ((max_name_len + 4) - names_str.length)}#{val_to_str(val)}\n"
|
|
317
|
+
end
|
|
318
|
+
|
|
275
319
|
def val_to_str(val)
|
|
276
320
|
if val.nil?
|
|
277
321
|
'nil'
|
|
@@ -301,45 +345,54 @@ module EverydayCliUtils
|
|
|
301
345
|
end
|
|
302
346
|
|
|
303
347
|
def defaults_option(file_path, names, settings = {})
|
|
304
|
-
|
|
305
|
-
settings[:file_path] = File.expand_path(file_path)
|
|
306
|
-
@options.register_special(4, :defaults, names, !settings.has_key?(:exit_on_save) || settings[:exit_on_save], 'Defaults set', settings,
|
|
307
|
-
->(opt, options) {
|
|
308
|
-
IO.write(opt.settings[:file_path], options.composite(:local, :arg).to_yaml)
|
|
309
|
-
}, ->(opt, options) {
|
|
310
|
-
unless opt.settings[:file_path].nil? || !File.exist?(opt.settings[:file_path])
|
|
311
|
-
options.update_all :local, YAML::load_file(opt.settings[:file_path])
|
|
312
|
-
end
|
|
313
|
-
})
|
|
348
|
+
defaults_options_helper(file_path, names, settings, 4, :defaults, 'Defaults set', :local)
|
|
314
349
|
end
|
|
315
350
|
|
|
316
351
|
def global_defaults_option(file_path, names, settings = {})
|
|
352
|
+
defaults_options_helper(file_path, names, settings, 3, :global_defaults, 'Global defaults set', :global)
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
def defaults_options_helper(file_path, names, settings, order, opt_name, print_on_exit_string, composite_name)
|
|
317
356
|
@options ||= OptionList.new
|
|
318
357
|
settings[:file_path] = File.expand_path(file_path)
|
|
319
|
-
@options.register_special(
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
358
|
+
@options.register_special(order, opt_name, names, key_absent_or_true(settings, :exit_on_save), print_on_exit_string, settings,
|
|
359
|
+
write_defaults_proc(composite_name), read_defaults_proc(composite_name))
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
def write_defaults_proc(composite_name)
|
|
363
|
+
->(opt, options) { IO.write(opt.settings[:file_path], options.composite(composite_name, :arg).to_yaml) }
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def read_defaults_proc(composite_name)
|
|
367
|
+
->(opt, options) {
|
|
368
|
+
file_path = opt.settings[:file_path]
|
|
369
|
+
options.update_all composite_name, YAML::load_file(file_path) unless file_path_nil_or_exists?(file_path)
|
|
370
|
+
}
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
def file_path_nil_or_exists?(file_path)
|
|
374
|
+
file_path.nil? || !File.exist?(file_path)
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
def key_absent_or_true(settings, key)
|
|
378
|
+
!settings.has_key?(key) || settings[key]
|
|
327
379
|
end
|
|
328
380
|
|
|
329
381
|
def show_defaults_option(names, settings = {})
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
puts options.show_defaults
|
|
334
|
-
})
|
|
382
|
+
show_info_helper(names, settings, 2, :show_defaults, :exit_on_show) { |_, options|
|
|
383
|
+
puts options.show_defaults
|
|
384
|
+
}
|
|
335
385
|
end
|
|
336
386
|
|
|
337
387
|
def help_option(names, settings = {})
|
|
388
|
+
show_info_helper(names, settings, 1, :help, :exit_on_print) { |_, options|
|
|
389
|
+
puts options.help
|
|
390
|
+
}
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
def show_info_helper(names, settings, order, opt_name, exit_on_sym, &block)
|
|
338
394
|
@options ||= OptionList.new
|
|
339
|
-
@options.register_special(
|
|
340
|
-
->(_, options) {
|
|
341
|
-
puts options.help
|
|
342
|
-
})
|
|
395
|
+
@options.register_special(order, opt_name, names, key_absent_or_true(settings, exit_on_sym), nil, settings, block)
|
|
343
396
|
end
|
|
344
397
|
|
|
345
398
|
def default_settings(settings = {})
|
|
@@ -15,6 +15,21 @@ class MethodOverrides
|
|
|
15
15
|
def get(obj)
|
|
16
16
|
OverridesInstance.new(@overrides, obj)
|
|
17
17
|
end
|
|
18
|
+
|
|
19
|
+
class << self
|
|
20
|
+
def register_override(s, s2, method_name, &block)
|
|
21
|
+
s.class_eval {
|
|
22
|
+
MethodOverrides.store_true_override(s, s2, method_name)
|
|
23
|
+
s.create_method(method_name.to_sym, &block)
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def store_true_override(s, s2, method_name)
|
|
28
|
+
original_method = s.instance_method(method_name.to_sym)
|
|
29
|
+
s2.true_overrides ||= MethodOverrides.new
|
|
30
|
+
s2.true_overrides.store_override(method_name.to_sym, original_method)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
18
33
|
end
|
|
19
34
|
|
|
20
35
|
class OverridesInstance
|
|
@@ -29,18 +44,25 @@ class OverridesInstance
|
|
|
29
44
|
end
|
|
30
45
|
|
|
31
46
|
def call_override(method_symbol, *args, &block)
|
|
32
|
-
|
|
33
|
-
overrides =
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
@overrides.has_key?(method_symbol.to_sym) ? -> {
|
|
48
|
+
overrides, ind, ovin = get_overrides_and_inds(method_symbol)
|
|
49
|
+
call_override_at_index(overrides, ind, ovin, args, &block)
|
|
50
|
+
}.call : @obj.send(method_symbol.to_sym, *args, &block)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def call_override_at_index(overrides, ind, ovin, args, &block)
|
|
54
|
+
Thread.current["overrides_ind_#{@obj.__id__}"] = @ind + ovin - 1
|
|
55
|
+
rv = overrides[ind].bind(@obj).call(*args, &block)
|
|
56
|
+
Thread.current["overrides_ind_#{@obj.__id__}"] = ovin
|
|
57
|
+
rv
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def get_overrides_and_inds(method_symbol)
|
|
61
|
+
overrides = @overrides[method_symbol.to_sym]
|
|
62
|
+
ind = overrides.count + (@ind - 1)
|
|
63
|
+
ovin = Thread.current["overrides_ind_#{@obj.__id__}"] || 0
|
|
64
|
+
ind += ovin
|
|
65
|
+
return overrides, ind, ovin
|
|
44
66
|
end
|
|
45
67
|
|
|
46
68
|
def method_missing(symbol, *args, &block)
|
|
@@ -66,15 +88,10 @@ class Object
|
|
|
66
88
|
end
|
|
67
89
|
|
|
68
90
|
def override(method_name, &block)
|
|
69
|
-
|
|
70
|
-
class << self
|
|
91
|
+
s = class << self
|
|
71
92
|
self
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
s2.true_overrides ||= MethodOverrides.new
|
|
75
|
-
s2.true_overrides.store_override(method_name.to_sym, original_method)
|
|
76
|
-
self.create_method(method_name.to_sym, &block)
|
|
77
|
-
}
|
|
93
|
+
end
|
|
94
|
+
MethodOverrides.register_override(s, self, method_name, &block)
|
|
78
95
|
end
|
|
79
96
|
|
|
80
97
|
class << self
|
|
@@ -91,12 +108,7 @@ class Object
|
|
|
91
108
|
end
|
|
92
109
|
|
|
93
110
|
def override(method_name, &block)
|
|
94
|
-
self
|
|
95
|
-
original_method = instance_method(method_name.to_sym)
|
|
96
|
-
self.true_overrides ||= MethodOverrides.new
|
|
97
|
-
self.true_overrides.store_override(method_name.to_sym, original_method)
|
|
98
|
-
self.create_method(method_name.to_sym, &block)
|
|
99
|
-
}
|
|
111
|
+
MethodOverrides.register_override(self, self, method_name, &block)
|
|
100
112
|
end
|
|
101
113
|
end
|
|
102
114
|
end
|
|
@@ -70,21 +70,21 @@ describe 'maputil' do
|
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
it 'provides a means of cloning a hash' do
|
|
73
|
-
hash
|
|
73
|
+
hash = { a: 1, b: 2, c: 3, d: 4, e: 5 }
|
|
74
74
|
cloned = hash.clone
|
|
75
75
|
expect(hash).to_not equal cloned
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
it 'provides a means of using map with a hash' do
|
|
79
|
-
hash
|
|
80
|
-
mapped
|
|
81
|
-
expected = { a: 2, b: 1, c: 4, d: 3, e: 6, f: 5}
|
|
79
|
+
hash = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 }
|
|
80
|
+
mapped = hash.hashmap { |v| v[1] + ((v[0] == :a || v[0] == :c || v[0] == :e) ? 1 : -1) }
|
|
81
|
+
expected = { a: 2, b: 1, c: 4, d: 3, e: 6, f: 5 }
|
|
82
82
|
expect(mapped).to eq expected
|
|
83
83
|
end
|
|
84
84
|
|
|
85
85
|
it 'provides a means of extending one hash with another' do
|
|
86
|
-
hash1
|
|
87
|
-
hash2
|
|
86
|
+
hash1 = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 }
|
|
87
|
+
hash2 = { a: 11, d: 14, f: 16 }
|
|
88
88
|
extended = hash2.extend_hash(hash1)
|
|
89
89
|
expected = { a: 11, b: 2, c: 3, d: 14, e: 5, f: 16 }
|
|
90
90
|
expect(extended).to eq expected
|
|
@@ -191,7 +191,7 @@ describe EverydayCliUtils::OptionUtil do
|
|
|
191
191
|
total = { opt1: true, opt2: %w(hi bye), opt3: 'bye', opt4: [5, 4] }
|
|
192
192
|
global_local = { opt1: false, opt2: %w(hi bye), opt3: 'bye', opt4: [5, 4] }
|
|
193
193
|
local = { opt1: true, opt2: %w(hi bye), opt3: 'bye', opt4: [4] }
|
|
194
|
-
local_arg
|
|
194
|
+
local_arg = { opt1: false, opt2: %w(hi bye), opt3: 'bye', opt4: [4] }
|
|
195
195
|
clean = { opt1: false, opt2: [], opt3: nil, opt4: [] }
|
|
196
196
|
clean2 = { opt1: true, opt2: [], opt3: nil, opt4: [] }
|
|
197
197
|
opt = Option1.new
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: everyday-cli-utils
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.8.
|
|
4
|
+
version: 1.8.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Eric Henderson
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2015-08-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -16,42 +16,42 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '1.
|
|
19
|
+
version: '1.10'
|
|
20
20
|
type: :development
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '1.
|
|
26
|
+
version: '1.10'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: rake
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '10.
|
|
33
|
+
version: '10.4'
|
|
34
34
|
type: :development
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '10.
|
|
40
|
+
version: '10.4'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: rspec
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
|
-
- - "
|
|
45
|
+
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '
|
|
47
|
+
version: '3.3'
|
|
48
48
|
type: :development
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
|
-
- - "
|
|
52
|
+
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '
|
|
54
|
+
version: '3.3'
|
|
55
55
|
description: A few CLI and general utilities. Includes a numbered-menu select loop
|
|
56
56
|
utility, a ANSI formatting escape code handler, a text-based histogram maker, k-means
|
|
57
57
|
and n-means (k-means with minimum optimal k) calculators, various collection utility
|
|
@@ -67,6 +67,7 @@ files:
|
|
|
67
67
|
- ".travis.yml"
|
|
68
68
|
- Gemfile
|
|
69
69
|
- Gemfile.ci
|
|
70
|
+
- Gemfile.lock
|
|
70
71
|
- LICENSE.txt
|
|
71
72
|
- README.md
|
|
72
73
|
- Rakefile
|
|
@@ -110,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
110
111
|
version: '0'
|
|
111
112
|
requirements: []
|
|
112
113
|
rubyforge_project:
|
|
113
|
-
rubygems_version: 2.4.
|
|
114
|
+
rubygems_version: 2.4.6
|
|
114
115
|
signing_key:
|
|
115
116
|
specification_version: 4
|
|
116
117
|
summary: A few CLI and general utils
|
|
@@ -121,3 +122,4 @@ test_files:
|
|
|
121
122
|
- spec/everyday-cli-utils/option_spec.rb
|
|
122
123
|
- spec/everyday-cli-utils/override_spec.rb
|
|
123
124
|
- spec/spec_helper.rb
|
|
125
|
+
has_rdoc:
|