aboutsummaryrefslogtreecommitdiffstats
path: root/railties/lib/vendor/thor-0.11.6/lib/thor/parser/option.rb
blob: 9e40ec73fa267b6bf115603a1b6fe4db2f01c0b3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
class Thor
  class Option < Argument #:nodoc:
    attr_reader :aliases, :group

    VALID_TYPES = [:boolean, :numeric, :hash, :array, :string]

    def initialize(name, description=nil, required=nil, type=nil, default=nil, banner=nil, group=nil, aliases=nil)
      super(name, description, required, type, default, banner)
      @aliases = [*aliases].compact
      @group   = group.to_s.capitalize if group
    end

    # This parse quick options given as method_options. It makes several
    # assumptions, but you can be more specific using the option method.
    #
    #   parse :foo => "bar"
    #   #=> Option foo with default value bar
    #
    #   parse [:foo, :baz] => "bar"
    #   #=> Option foo with default value bar and alias :baz
    #
    #   parse :foo => :required
    #   #=> Required option foo without default value
    #
    #   parse :foo => 2
    #   #=> Option foo with default value 2 and type numeric
    #
    #   parse :foo => :numeric
    #   #=> Option foo without default value and type numeric
    #
    #   parse :foo => true
    #   #=> Option foo with default value true and type boolean
    #
    # The valid types are :boolean, :numeric, :hash, :array and :string. If none
    # is given a default type is assumed. This default type accepts arguments as
    # string (--foo=value) or booleans (just --foo).
    #
    # By default all options are optional, unless :required is given.
    # 
    def self.parse(key, value)
      if key.is_a?(Array)
        name, *aliases = key
      else
        name, aliases = key, []
      end

      name    = name.to_s
      default = value

      type = case value
        when Symbol
          default  = nil

          if VALID_TYPES.include?(value)
            value
          elsif required = (value == :required)
            :string
          elsif value == :optional
            # TODO Remove this warning in the future.
            warn "Optional type is deprecated. Choose :boolean or :string instead. Assumed to be :boolean."
            :boolean
          end
        when TrueClass, FalseClass
          :boolean
        when Numeric
          :numeric
        when Hash, Array, String
          value.class.name.downcase.to_sym
      end

      self.new(name.to_s, nil, required, type, default, nil, nil, aliases)
    end

    def switch_name
      @switch_name ||= dasherized? ? name : dasherize(name)
    end

    def human_name
      @human_name ||= dasherized? ? undasherize(name) : name
    end

    def usage(padding=0)
      sample = if banner && !banner.to_s.empty?
        "#{switch_name}=#{banner}"
      else
        switch_name
      end

      sample = "[#{sample}]" unless required?

      if aliases.empty?
        (" " * padding) << sample
      else
        "#{aliases.join(', ')}, #{sample}"
      end
    end

    # Allow some type predicates as: boolean?, string? and etc.
    #
    def method_missing(method, *args, &block)
      given = method.to_s.sub(/\?$/, '').to_sym
      if valid_type?(given)
        self.type == given
      else
        super
      end
    end

    protected

      def validate!
        raise ArgumentError, "An option cannot be boolean and required." if boolean? && required?
      end

      def valid_type?(type)
        VALID_TYPES.include?(type.to_sym)
      end

      def dasherized?
        name.index('-') == 0
      end

      def undasherize(str)
        str.sub(/^-{1,2}/, '')
      end

      def dasherize(str)
        (str.length > 1 ? "--" : "-") + str.gsub('_', '-')
      end

  end
end