qthor 0.19.1.5
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/.document +5 -0
- data/CHANGELOG.md +163 -0
- data/CONTRIBUTING.md +15 -0
- data/LICENSE.md +20 -0
- data/README.md +47 -0
- data/bin/qthor +6 -0
- data/lib/thor.rb +490 -0
- data/lib/thor/actions.rb +319 -0
- data/lib/thor/actions/create_file.rb +103 -0
- data/lib/thor/actions/create_link.rb +59 -0
- data/lib/thor/actions/directory.rb +118 -0
- data/lib/thor/actions/empty_directory.rb +135 -0
- data/lib/thor/actions/file_manipulation.rb +327 -0
- data/lib/thor/actions/inject_into_file.rb +107 -0
- data/lib/thor/base.rb +656 -0
- data/lib/thor/command.rb +133 -0
- data/lib/thor/core_ext/hash_with_indifferent_access.rb +85 -0
- data/lib/thor/core_ext/io_binary_read.rb +10 -0
- data/lib/thor/core_ext/ordered_hash.rb +129 -0
- data/lib/thor/error.rb +32 -0
- data/lib/thor/group.rb +281 -0
- data/lib/thor/invocation.rb +178 -0
- data/lib/thor/line_editor.rb +17 -0
- data/lib/thor/line_editor/basic.rb +35 -0
- data/lib/thor/line_editor/readline.rb +88 -0
- data/lib/thor/parser.rb +4 -0
- data/lib/thor/parser/argument.rb +73 -0
- data/lib/thor/parser/arguments.rb +176 -0
- data/lib/thor/parser/option.rb +140 -0
- data/lib/thor/parser/options.rb +218 -0
- data/lib/thor/rake_compat.rb +71 -0
- data/lib/thor/runner.rb +322 -0
- data/lib/thor/shell.rb +81 -0
- data/lib/thor/shell/basic.rb +430 -0
- data/lib/thor/shell/color.rb +149 -0
- data/lib/thor/shell/html.rb +126 -0
- data/lib/thor/util.rb +267 -0
- data/lib/thor/version.rb +3 -0
- data/thor.gemspec +21 -0
- metadata +99 -0
@@ -0,0 +1,178 @@
|
|
1
|
+
class Thor
|
2
|
+
module Invocation
|
3
|
+
def self.included(base) #:nodoc:
|
4
|
+
base.extend ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
# This method is responsible for receiving a name and find the proper
|
9
|
+
# class and command for it. The key is an optional parameter which is
|
10
|
+
# available only in class methods invocations (i.e. in Thor::Group).
|
11
|
+
def prepare_for_invocation(key, name) #:nodoc:
|
12
|
+
case name
|
13
|
+
when Symbol, String
|
14
|
+
Thor::Util.find_class_and_command_by_namespace(name.to_s, !key)
|
15
|
+
else
|
16
|
+
name
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Make initializer aware of invocations and the initialization args.
|
22
|
+
def initialize(args = [], options = {}, config = {}, &block) #:nodoc:
|
23
|
+
@_invocations = config[:invocations] || Hash.new { |h, k| h[k] = [] }
|
24
|
+
@_initializer = [args, options, config]
|
25
|
+
super
|
26
|
+
end
|
27
|
+
|
28
|
+
# Make the current command chain accessible with in a Thor-(sub)command
|
29
|
+
def current_command_chain
|
30
|
+
@_invocations.values.flatten.map(&:to_sym)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Receives a name and invokes it. The name can be a string (either "command" or
|
34
|
+
# "namespace:command"), a Thor::Command, a Class or a Thor instance. If the
|
35
|
+
# command cannot be guessed by name, it can also be supplied as second argument.
|
36
|
+
#
|
37
|
+
# You can also supply the arguments, options and configuration values for
|
38
|
+
# the command to be invoked, if none is given, the same values used to
|
39
|
+
# initialize the invoker are used to initialize the invoked.
|
40
|
+
#
|
41
|
+
# When no name is given, it will invoke the default command of the current class.
|
42
|
+
#
|
43
|
+
# ==== Examples
|
44
|
+
#
|
45
|
+
# class A < Thor
|
46
|
+
# def foo
|
47
|
+
# invoke :bar
|
48
|
+
# invoke "b:hello", ["Erik"]
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# def bar
|
52
|
+
# invoke "b:hello", ["Erik"]
|
53
|
+
# end
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# class B < Thor
|
57
|
+
# def hello(name)
|
58
|
+
# puts "hello #{name}"
|
59
|
+
# end
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# You can notice that the method "foo" above invokes two commands: "bar",
|
63
|
+
# which belongs to the same class and "hello" which belongs to the class B.
|
64
|
+
#
|
65
|
+
# By using an invocation system you ensure that a command is invoked only once.
|
66
|
+
# In the example above, invoking "foo" will invoke "b:hello" just once, even
|
67
|
+
# if it's invoked later by "bar" method.
|
68
|
+
#
|
69
|
+
# When class A invokes class B, all arguments used on A initialization are
|
70
|
+
# supplied to B. This allows lazy parse of options. Let's suppose you have
|
71
|
+
# some rspec commands:
|
72
|
+
#
|
73
|
+
# class Rspec < Thor::Group
|
74
|
+
# class_option :mock_framework, :type => :string, :default => :rr
|
75
|
+
#
|
76
|
+
# def invoke_mock_framework
|
77
|
+
# invoke "rspec:#{options[:mock_framework]}"
|
78
|
+
# end
|
79
|
+
# end
|
80
|
+
#
|
81
|
+
# As you noticed, it invokes the given mock framework, which might have its
|
82
|
+
# own options:
|
83
|
+
#
|
84
|
+
# class Rspec::RR < Thor::Group
|
85
|
+
# class_option :style, :type => :string, :default => :mock
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# Since it's not rspec concern to parse mock framework options, when RR
|
89
|
+
# is invoked all options are parsed again, so RR can extract only the options
|
90
|
+
# that it's going to use.
|
91
|
+
#
|
92
|
+
# If you want Rspec::RR to be initialized with its own set of options, you
|
93
|
+
# have to do that explicitly:
|
94
|
+
#
|
95
|
+
# invoke "rspec:rr", [], :style => :foo
|
96
|
+
#
|
97
|
+
# Besides giving an instance, you can also give a class to invoke:
|
98
|
+
#
|
99
|
+
# invoke Rspec::RR, [], :style => :foo
|
100
|
+
#
|
101
|
+
def invoke(name = nil, *args)
|
102
|
+
if name.nil?
|
103
|
+
warn "[Thor] Calling invoke() without argument is deprecated. Please use invoke_all instead.\n#{caller.join("\n")}"
|
104
|
+
return invoke_all
|
105
|
+
end
|
106
|
+
|
107
|
+
args.unshift(nil) if args.first.is_a?(Array) || args.first.nil?
|
108
|
+
command, args, opts, config = args
|
109
|
+
|
110
|
+
klass, command = _retrieve_class_and_command(name, command)
|
111
|
+
fail "Missing Thor class for invoke #{name}" unless klass
|
112
|
+
fail "Expected Thor class, got #{klass}" unless klass <= Thor::Base
|
113
|
+
|
114
|
+
args, opts, config = _parse_initialization_options(args, opts, config)
|
115
|
+
klass.send(:dispatch, command, args, opts, config) do |instance|
|
116
|
+
instance.parent_options = options
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Invoke the given command if the given args.
|
121
|
+
def invoke_command(command, *args) #:nodoc:
|
122
|
+
current = @_invocations[self.class]
|
123
|
+
|
124
|
+
unless current.include?(command.name)
|
125
|
+
current << command.name
|
126
|
+
command.run(self, *args)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
alias_method :invoke_task, :invoke_command
|
130
|
+
|
131
|
+
# Invoke all commands for the current instance.
|
132
|
+
def invoke_all #:nodoc:
|
133
|
+
self.class.all_commands.map { |_, command| invoke_command(command) }
|
134
|
+
end
|
135
|
+
|
136
|
+
# Invokes using shell padding.
|
137
|
+
def invoke_with_padding(*args)
|
138
|
+
with_padding { invoke(*args) }
|
139
|
+
end
|
140
|
+
|
141
|
+
protected
|
142
|
+
|
143
|
+
# Configuration values that are shared between invocations.
|
144
|
+
def _shared_configuration #:nodoc:
|
145
|
+
{:invocations => @_invocations}
|
146
|
+
end
|
147
|
+
|
148
|
+
# This method simply retrieves the class and command to be invoked.
|
149
|
+
# If the name is nil or the given name is a command in the current class,
|
150
|
+
# use the given name and return self as class. Otherwise, call
|
151
|
+
# prepare_for_invocation in the current class.
|
152
|
+
def _retrieve_class_and_command(name, sent_command = nil) #:nodoc:
|
153
|
+
case
|
154
|
+
when name.nil?
|
155
|
+
[self.class, nil]
|
156
|
+
when self.class.all_commands[name.to_s]
|
157
|
+
[self.class, name.to_s]
|
158
|
+
else
|
159
|
+
klass, command = self.class.prepare_for_invocation(nil, name)
|
160
|
+
[klass, command || sent_command]
|
161
|
+
end
|
162
|
+
end
|
163
|
+
alias_method :_retrieve_class_and_task, :_retrieve_class_and_command
|
164
|
+
|
165
|
+
# Initialize klass using values stored in the @_initializer.
|
166
|
+
def _parse_initialization_options(args, opts, config) #:nodoc:
|
167
|
+
stored_args, stored_opts, stored_config = @_initializer
|
168
|
+
|
169
|
+
args ||= stored_args.dup
|
170
|
+
opts ||= stored_opts.dup
|
171
|
+
|
172
|
+
config ||= {}
|
173
|
+
config = stored_config.merge(_shared_configuration).merge!(config)
|
174
|
+
|
175
|
+
[args, opts, config]
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "thor/line_editor/basic"
|
2
|
+
require "thor/line_editor/readline"
|
3
|
+
|
4
|
+
class Thor
|
5
|
+
module LineEditor
|
6
|
+
def self.readline(prompt, options = {})
|
7
|
+
best_available.new(prompt, options).readline
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.best_available
|
11
|
+
[
|
12
|
+
Thor::LineEditor::Readline,
|
13
|
+
Thor::LineEditor::Basic
|
14
|
+
].detect(&:available?)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class Thor
|
2
|
+
module LineEditor
|
3
|
+
class Basic
|
4
|
+
attr_reader :prompt, :options
|
5
|
+
|
6
|
+
def self.available?
|
7
|
+
true
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(prompt, options)
|
11
|
+
@prompt = prompt
|
12
|
+
@options = options
|
13
|
+
end
|
14
|
+
|
15
|
+
def readline
|
16
|
+
$stdout.print(prompt)
|
17
|
+
get_input
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def get_input
|
23
|
+
if echo?
|
24
|
+
$stdin.gets
|
25
|
+
else
|
26
|
+
$stdin.noecho(&:gets)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def echo?
|
31
|
+
options.fetch(:echo, true)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
begin
|
2
|
+
require "readline"
|
3
|
+
rescue LoadError
|
4
|
+
end
|
5
|
+
|
6
|
+
class Thor
|
7
|
+
module LineEditor
|
8
|
+
class Readline < Basic
|
9
|
+
def self.available?
|
10
|
+
Object.const_defined?(:Readline)
|
11
|
+
end
|
12
|
+
|
13
|
+
def readline
|
14
|
+
if echo?
|
15
|
+
::Readline.completion_append_character = nil
|
16
|
+
# Ruby 1.8.7 does not allow Readline.completion_proc= to receive nil.
|
17
|
+
if complete = completion_proc
|
18
|
+
::Readline.completion_proc = complete
|
19
|
+
end
|
20
|
+
::Readline.readline(prompt, add_to_history?)
|
21
|
+
else
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def add_to_history?
|
29
|
+
options.fetch(:add_to_history, true)
|
30
|
+
end
|
31
|
+
|
32
|
+
def completion_proc
|
33
|
+
if use_path_completion?
|
34
|
+
proc { |text| PathCompletion.new(text).matches }
|
35
|
+
elsif completion_options.any?
|
36
|
+
proc do |text|
|
37
|
+
completion_options.select { |option| option.start_with?(text) }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def completion_options
|
43
|
+
options.fetch(:limited_to, [])
|
44
|
+
end
|
45
|
+
|
46
|
+
def use_path_completion?
|
47
|
+
options.fetch(:path, false)
|
48
|
+
end
|
49
|
+
|
50
|
+
class PathCompletion
|
51
|
+
attr_reader :text
|
52
|
+
private :text
|
53
|
+
|
54
|
+
def initialize(text)
|
55
|
+
@text = text
|
56
|
+
end
|
57
|
+
|
58
|
+
def matches
|
59
|
+
relative_matches
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def relative_matches
|
65
|
+
absolute_matches.map { |path| path.sub(base_path, "") }
|
66
|
+
end
|
67
|
+
|
68
|
+
def absolute_matches
|
69
|
+
Dir[glob_pattern].map do |path|
|
70
|
+
if File.directory?(path)
|
71
|
+
"#{path}/"
|
72
|
+
else
|
73
|
+
path
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def glob_pattern
|
79
|
+
"#{base_path}#{text}*"
|
80
|
+
end
|
81
|
+
|
82
|
+
def base_path
|
83
|
+
"#{Dir.pwd}/"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/thor/parser.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
class Thor
|
2
|
+
class Argument #:nodoc:
|
3
|
+
VALID_TYPES = [:numeric, :hash, :array, :string]
|
4
|
+
|
5
|
+
attr_reader :name, :description, :enum, :required, :type, :default, :banner
|
6
|
+
alias_method :human_name, :name
|
7
|
+
|
8
|
+
def initialize(name, options = {})
|
9
|
+
class_name = self.class.name.split("::").last
|
10
|
+
|
11
|
+
type = options[:type]
|
12
|
+
|
13
|
+
fail ArgumentError, "#{class_name} name can't be nil." if name.nil?
|
14
|
+
fail ArgumentError, "Type :#{type} is not valid for #{class_name.downcase}s." if type && !valid_type?(type)
|
15
|
+
|
16
|
+
@name = name.to_s
|
17
|
+
@description = options[:desc]
|
18
|
+
@required = options.key?(:required) ? options[:required] : true
|
19
|
+
@type = (type || :string).to_sym
|
20
|
+
@default = options[:default]
|
21
|
+
@banner = options[:banner] || default_banner
|
22
|
+
@enum = options[:enum]
|
23
|
+
|
24
|
+
validate! # Trigger specific validations
|
25
|
+
end
|
26
|
+
|
27
|
+
def usage
|
28
|
+
required? ? banner : "[#{banner}]"
|
29
|
+
end
|
30
|
+
|
31
|
+
def required?
|
32
|
+
required
|
33
|
+
end
|
34
|
+
|
35
|
+
def show_default?
|
36
|
+
case default
|
37
|
+
when Array, String, Hash
|
38
|
+
!default.empty?
|
39
|
+
else
|
40
|
+
default
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
protected
|
45
|
+
|
46
|
+
def validate!
|
47
|
+
if required? && !default.nil?
|
48
|
+
fail ArgumentError, "An argument cannot be required and have default value."
|
49
|
+
elsif @enum && !@enum.is_a?(Array)
|
50
|
+
fail ArgumentError, "An argument cannot have an enum other than an array."
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def valid_type?(type)
|
55
|
+
self.class::VALID_TYPES.include?(type.to_sym)
|
56
|
+
end
|
57
|
+
|
58
|
+
def default_banner
|
59
|
+
case type
|
60
|
+
when :boolean
|
61
|
+
nil
|
62
|
+
when :string, :default
|
63
|
+
human_name.upcase
|
64
|
+
when :numeric
|
65
|
+
"N"
|
66
|
+
when :hash
|
67
|
+
"key:value"
|
68
|
+
when :array
|
69
|
+
"one two three"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
class Thor
|
2
|
+
class Arguments #:nodoc: # rubocop:disable ClassLength
|
3
|
+
NUMERIC = /[-+]?(\d*\.\d+|\d+)/
|
4
|
+
|
5
|
+
# Receives an array of args and returns two arrays, one with arguments
|
6
|
+
# and one with switches.
|
7
|
+
#
|
8
|
+
def self.split(args)
|
9
|
+
arguments = []
|
10
|
+
|
11
|
+
args.each do |item|
|
12
|
+
break if item =~ /^-/
|
13
|
+
arguments << item
|
14
|
+
end
|
15
|
+
|
16
|
+
[arguments, args[Range.new(arguments.size, -1)]]
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.parse(*args)
|
20
|
+
to_parse = args.pop
|
21
|
+
new(*args).parse(to_parse)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Takes an array of Thor::Argument objects.
|
25
|
+
#
|
26
|
+
def initialize(arguments = [])
|
27
|
+
@assigns, @non_assigned_required = {}, []
|
28
|
+
@switches = arguments
|
29
|
+
|
30
|
+
arguments.each do |argument|
|
31
|
+
if !argument.default.nil?
|
32
|
+
@assigns[argument.human_name] = argument.default
|
33
|
+
elsif argument.required?
|
34
|
+
@non_assigned_required << argument
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse(args)
|
40
|
+
@pile = args.dup
|
41
|
+
|
42
|
+
@switches.each do |argument|
|
43
|
+
break unless peek
|
44
|
+
@non_assigned_required.delete(argument)
|
45
|
+
@assigns[argument.human_name] = send(:"parse_#{argument.type}", argument.human_name)
|
46
|
+
end
|
47
|
+
|
48
|
+
check_requirement!
|
49
|
+
@assigns
|
50
|
+
end
|
51
|
+
|
52
|
+
def remaining # rubocop:disable TrivialAccessors
|
53
|
+
@pile
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def no_or_skip?(arg)
|
59
|
+
arg =~ /^--(no|skip)-([-\w]+)$/
|
60
|
+
$2
|
61
|
+
end
|
62
|
+
|
63
|
+
def last?
|
64
|
+
@pile.empty?
|
65
|
+
end
|
66
|
+
|
67
|
+
def peek
|
68
|
+
@pile.first
|
69
|
+
end
|
70
|
+
|
71
|
+
def shift
|
72
|
+
@pile.shift
|
73
|
+
end
|
74
|
+
|
75
|
+
def unshift(arg)
|
76
|
+
if arg.kind_of?(Array)
|
77
|
+
@pile = arg + @pile
|
78
|
+
else
|
79
|
+
@pile.unshift(arg)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def current_is_value?
|
84
|
+
peek && peek.to_s !~ /^-/
|
85
|
+
end
|
86
|
+
|
87
|
+
# Runs through the argument array getting strings that contains ":" and
|
88
|
+
# mark it as a hash:
|
89
|
+
#
|
90
|
+
# [ "name:string", "age:integer" ]
|
91
|
+
#
|
92
|
+
# Becomes:
|
93
|
+
#
|
94
|
+
# { "name" => "string", "age" => "integer" }
|
95
|
+
#
|
96
|
+
def parse_hash(name)
|
97
|
+
return shift if peek.is_a?(Hash)
|
98
|
+
hash = {}
|
99
|
+
|
100
|
+
while current_is_value? && peek.include?(":")
|
101
|
+
key, value = shift.split(":", 2)
|
102
|
+
fail MalformattedArgumentError, "You can't specify '#{key}' more than once in option '#{name}'; got #{key}:#{hash[key]} and #{key}:#{value}" if hash.include? key
|
103
|
+
hash[key] = value
|
104
|
+
end
|
105
|
+
hash
|
106
|
+
end
|
107
|
+
|
108
|
+
# Runs through the argument array getting all strings until no string is
|
109
|
+
# found or a switch is found.
|
110
|
+
#
|
111
|
+
# ["a", "b", "c"]
|
112
|
+
#
|
113
|
+
# And returns it as an array:
|
114
|
+
#
|
115
|
+
# ["a", "b", "c"]
|
116
|
+
#
|
117
|
+
def parse_array(name)
|
118
|
+
return shift if peek.is_a?(Array)
|
119
|
+
array = []
|
120
|
+
array << shift while current_is_value?
|
121
|
+
array
|
122
|
+
end
|
123
|
+
|
124
|
+
# Check if the peek is numeric format and return a Float or Integer.
|
125
|
+
# Check if the peek is included in enum if enum is provided.
|
126
|
+
# Otherwise raises an error.
|
127
|
+
#
|
128
|
+
def parse_numeric(name)
|
129
|
+
return shift if peek.is_a?(Numeric)
|
130
|
+
|
131
|
+
unless peek =~ NUMERIC && $& == peek
|
132
|
+
fail MalformattedArgumentError, "Expected numeric value for '#{name}'; got #{peek.inspect}"
|
133
|
+
end
|
134
|
+
|
135
|
+
value = $&.index(".") ? shift.to_f : shift.to_i
|
136
|
+
if @switches.is_a?(Hash) && switch = @switches[name]
|
137
|
+
if switch.enum && !switch.enum.include?(value)
|
138
|
+
fail MalformattedArgumentError, "Expected '#{name}' to be one of #{switch.enum.join(', ')}; got #{value}"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
value
|
142
|
+
end
|
143
|
+
|
144
|
+
# Parse string:
|
145
|
+
# for --string-arg, just return the current value in the pile
|
146
|
+
# for --no-string-arg, nil
|
147
|
+
# Check if the peek is included in enum if enum is provided. Otherwise raises an error.
|
148
|
+
#
|
149
|
+
def parse_string(name)
|
150
|
+
if no_or_skip?(name)
|
151
|
+
nil
|
152
|
+
else
|
153
|
+
value = shift
|
154
|
+
if @switches.is_a?(Hash) && switch = @switches[name] # rubocop:disable AssignmentInCondition
|
155
|
+
if switch.enum && !switch.enum.include?(value)
|
156
|
+
fail MalformattedArgumentError, "Expected '#{name}' to be one of #{switch.enum.join(', ')}; got #{value}"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
value
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# Raises an error if @non_assigned_required array is not empty.
|
164
|
+
#
|
165
|
+
def check_requirement!
|
166
|
+
unless @non_assigned_required.empty?
|
167
|
+
names = @non_assigned_required.map do |o|
|
168
|
+
o.respond_to?(:switch_name) ? o.switch_name : o.human_name
|
169
|
+
end.join("', '")
|
170
|
+
|
171
|
+
class_name = self.class.name.split("::").last.downcase
|
172
|
+
fail RequiredArgumentMissingError, "No value provided for required #{class_name} '#{names}'"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|