Skip to content

Commit 4fb8401

Browse files
committed
Always check default type. Deprecate incompatible types without explicit option given [#621]
1 parent 57fe753 commit 4fb8401

File tree

4 files changed

+47
-11
lines changed

4 files changed

+47
-11
lines changed

lib/thor.rb

+7
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,13 @@ def disable_required_check?(command) #:nodoc:
339339
command && disable_required_check.include?(command.name.to_sym)
340340
end
341341

342+
def deprecation_warning(message) #:nodoc:
343+
unless ENV['THOR_SILENCE_DEPRECATION']
344+
warn "Deprecation warning: #{message}\n" +
345+
'You can silence deprecations warning by setting the environment variable THOR_SILENCE_DEPRECATION.'
346+
end
347+
end
348+
342349
protected
343350

344351
def stop_on_unknown_option #:nodoc:

lib/thor/base.rb

+9-6
Original file line numberDiff line numberDiff line change
@@ -153,17 +153,20 @@ def check_unknown_options?(config) #:nodoc:
153153

154154
# If you want to raise an error when the default value of an option does not match
155155
# the type call check_default_type!
156-
# This is disabled by default for compatibility.
156+
# This will be the default; for compatibility a deprecation warning is issued if necessary.
157157
def check_default_type!
158158
@check_default_type = true
159159
end
160160

161-
def check_default_type #:nodoc:
162-
@check_default_type ||= from_superclass(:check_default_type, false)
161+
# If you want to use defaults that don't match the type of an option,
162+
# either specify `check_default_type: false` or call `allow_incompatible_default_type!`
163+
def allow_incompatible_default_type!
164+
@check_default_type = false
163165
end
164166

165-
def check_default_type? #:nodoc:
166-
!!check_default_type
167+
def check_default_type #:nodoc:
168+
@check_default_type = from_superclass(:check_default_type, nil) unless defined?(@check_default_type)
169+
@check_default_type
167170
end
168171

169172
# If true, option parsing is suspended as soon as an unknown option or a
@@ -564,7 +567,7 @@ def is_thor_reserved_word?(word, type) #:nodoc:
564567
# options<Hash>:: Described in both class_option and method_option.
565568
# scope<Hash>:: Options hash that is being built up
566569
def build_option(name, options, scope) #:nodoc:
567-
scope[name] = Thor::Option.new(name, options.merge(:check_default_type => check_default_type?))
570+
scope[name] = Thor::Option.new(name, {:check_default_type => check_default_type}.merge!(options))
568571
end
569572

570573
# Receives a hash of options, parse them and add to the scope. This is a

lib/thor/parser/option.rb

+11-3
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ def #{type}?
111111

112112
def validate!
113113
raise ArgumentError, "An option cannot be boolean and required." if boolean? && required?
114-
validate_default_type! if @check_default_type
114+
validate_default_type!
115115
end
116116

117117
def validate_default_type!
@@ -127,8 +127,16 @@ def validate_default_type!
127127
when Hash, Array, String
128128
@default.class.name.downcase.to_sym
129129
end
130-
131-
raise ArgumentError, "Expected #{@type} default value for '#{switch_name}'; got #{@default.inspect} (#{default_type})" unless default_type == @type
130+
if default_type != @type
131+
err = "Expected #{@type} default value for '#{switch_name}'; got #{@default.inspect} (#{default_type})"
132+
if @check_default_type
133+
raise ArgumentError, err
134+
elsif @check_default_type == nil
135+
Thor.deprecation_warning "#{err}.\n" +
136+
'This will be rejected in the future unless you explicitly pass the options `check_default_type: false`' +
137+
' or call `allow_incompatible_default_type!` in your code'
138+
end
139+
end
132140
end
133141

134142
def dasherized?

spec/thor_spec.rb

+20-2
Original file line numberDiff line numberDiff line change
@@ -694,12 +694,30 @@ def unknown(*args)
694694
expect(klass.start(%w(unknown foo --bar baz))).to eq(%w(foo))
695695
end
696696

697-
it "does not check the default type when check_default_type! is not called" do
697+
it "issues a deprecation warning on incompatible types by default" do
698698
expect do
699699
Class.new(Thor) do
700700
option "bar", :type => :numeric, :default => "foo"
701701
end
702-
end.not_to raise_error
702+
end.to output(/^Deprecation warning/).to_stderr
703+
end
704+
705+
it "allows incompatible types if allow_incompatible_default_type! is called" do
706+
expect do
707+
Class.new(Thor) do
708+
allow_incompatible_default_type!
709+
710+
option "bar", :type => :numeric, :default => "foo"
711+
end
712+
end.not_to output.to_stderr
713+
end
714+
715+
it "allows incompatible types if `check_default_type: false` is given" do
716+
expect do
717+
Class.new(Thor) do
718+
option "bar", :type => :numeric, :default => "foo", :check_default_type => false
719+
end
720+
end.not_to output.to_stderr
703721
end
704722

705723
it "checks the default type when check_default_type! is called" do

0 commit comments

Comments
 (0)