Class: Opto::Group

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/opto/group.rb

Overview

A group of Opto::Option instances. Members of Groups can see their relatives and their values. Such as `option.value_of('another_option')`

Most Array instance methods are delegated, such as .map, .each, .find etc.

Instance Method Summary collapse

Constructor Details

#initialize(*opts) ⇒ Opto::Group

Initialize a new Option Group. You can also pass in :defaults.

Parameters:

  • opts (Array<Hash,Opto::Option>, Hash, NilClass)

    An array of Option definition hashes or Option objects or a hash like { var_name: { opts } }.


20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/opto/group.rb', line 20

def initialize(*opts)
  case opts.first
  when NilClass
  when Hash
    defaults.merge!(opts.first.delete(:defaults)) if opts.first.key?(:defaults)
    setters.merge!(opts.first.delete(:setters)) if opts.first.key?(:setters)
    resolvers.merge!(opts.first.delete(:resolvers)) if opts.first.key?(:resolvers)
    options.concat(opts.first.map {|k,v| Option.new({name: k.to_s, group: self}.merge(v))})
  when ::Array
    if opts.last.is_a?(Hash) && !opts.last.key?(:type)
      opts.pop.tap do |settings|
        defaults.merge!(settings[:defaults]) if settings.key?(:defaults)
        setters.merge!(settings[:setters]) if settings.key?(:setters)
        resolvers.merge!(settings[:resolvers]) if settings.key?(:resolvers)
      end
    end
    if opts.first.kind_of?(Array)
      options.concat(opts.first.map { |opt| opt.kind_of?(Opto::Option) ? opt : Option.new(opt.merge(group: self)) })
    end
  else
    raise TypeError, "Invalid type #{opts.class} for Opto::Group.new"
  end
end

Instance Method Details

#all_true?(conditions) ⇒ Boolean

Returns:

  • (Boolean)

144
145
146
# File 'lib/opto/group.rb', line 144

def all_true?(conditions)
  normalize_ifs(conditions).all? { |s| s.call(self) == true }
end

#any_true?(conditions) ⇒ Boolean

Returns:

  • (Boolean)

140
141
142
# File 'lib/opto/group.rb', line 140

def any_true?(conditions)
  normalize_ifs(conditions).any? { |s| s.call(self) == true }
end

#build_option(args = {}) ⇒ Opto::Option

Initialize a new Option to this group. Takes the same arguments as Opto::Option

Parameters:

  • option_definition (Hash)

Returns:


102
103
104
105
# File 'lib/opto/group.rb', line 102

def build_option(args={})
  options << Option.new(args.merge(group: self))
  options.last
end

#defaultsObject


56
57
58
# File 'lib/opto/group.rb', line 56

def defaults
  @defaults ||= {}
end

#errorsHash

Collect validation errors from members

Returns:

  • (Hash)

    { option_name => { validator_name => “Too short” } }


68
69
70
# File 'lib/opto/group.rb', line 68

def errors
  Hash[*options_with_errors.flat_map {|o| [o.name, o.errors] }]
end

#normalize_ifs(ifs) ⇒ Object


148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/opto/group.rb', line 148

def normalize_ifs(ifs)
  case ifs
  when NilClass
    []
  when ::Array
    ifs.map do |iff|
      lambda { |grp| grp.option(iff).true?  }
    end
  when Hash
    ifs.each_with_object([]) do |(k, v), arr|
      if v.kind_of?(Hash)
        if v.has_key?(:lt)
          arr << lambda { |grp| grp.value_of(k.to_s) < v[:lt] }
        end

        if v.has_key?(:lte)
          arr << lambda { |grp| grp.value_of(k.to_s) <= v[:lte] }
        end

        if v.has_key?(:gt)
          arr << lambda { |grp| grp.value_of(k.to_s) > v[:gt] }
        end

        if v.has_key?(:gte)
          arr << lambda { |grp| grp.value_of(k.to_s) > v[:gte] }
        end

        if v.has_key?(:eq)
          arr << lambda { |grp| grp.value_of(k.to_s) == v[:eq] }
        end

        if v.has_key?(:ne)
          arr << lambda { |grp| grp.value_of(k.to_s) != v[:ne] }
        end

        if v.has_key?(:start_with)
          arr << lambda { |grp| grp.value_of(k.to_s).to_s.start_with?(v[:start_with]) }
        end

        if v.has_key?(:end_with)
          arr << lambda { |grp| grp.value_of(k.to_s).to_s.end_with?(v[:end_with]) }
        end

        if v.has_key?(:contain)
          arr << lambda { |grp| grp.value_of(k.to_s).kind_of?(::Array) ? grp.value_of(k.to_s).include?(v[:contain]) : grp.value_of(k.to_s).to_s.include?(v[:contain]) }
        end

        if v.has_key?(:any_of)
          arr << lambda do |grp|
            if v[:any_of].kind_of?(String)
              arr = v[:any_of].split(",")
            elsif v[:any_of].kind_of?(::Array)
              arr = v[:any_of]
            else
              raise TypeError, "Invalid list for 'any_of'. Expected: Array or a comma separated string"
            end
            arr.include?(grp.value_of(k.to_s))
          end
        end
      else
        arr << lambda { |grp| grp.value_of(k.to_s) == v }
      end
    end
  when String, Symbol
    normalize_ifs([ifs])
  else
    raise TypeError, "Invalid syntax for conditional"
  end
end

#option(option_name) ⇒ Opto::Option

Find a member by name @param  option_name

Returns:


110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/opto/group.rb', line 110

def option(option_name)
  if option_name.to_s.include?('.')
    parts = option_name.to_s.split('.')
    var_name = parts.pop
    group = parts.inject(self) do |base, part|
      grp = base.option(part).value
      if grp.nil?
        raise NameError, "No such group: #{base.name}.#{part}"
      elsif grp.kind_of?(Opto::Group)
        grp
      else
        raise TypeError, "Is not a group: #{base.name}.#{part}"
      end
    end
  else
    group = self
    var_name = option_name
  end

  group.options.find { |opt| opt.name == var_name }
end

#optionsObject


44
45
46
# File 'lib/opto/group.rb', line 44

def options
  @options ||= []
end

#options_with_errorsArray

Enumerate over all the options that are not valid

Returns:

  • (Array)

74
75
76
# File 'lib/opto/group.rb', line 74

def options_with_errors
  options.reject(&:valid?)
end

#resolversObject


52
53
54
# File 'lib/opto/group.rb', line 52

def resolvers
  @resolvers ||= {}
end

#runObject

Runs outputters for all valid non-skipped options


95
96
97
# File 'lib/opto/group.rb', line 95

def run
  options.reject(&:skip?).select(&:valid?).each(&:output)
end

#settersObject


48
49
50
# File 'lib/opto/group.rb', line 48

def setters
  @setters ||= {}
end

#to_a(with_errors: false, with_values: false) ⇒ Array<Hash>

Convert Group to an Array of Hashes (by calling .to_h on each member)

Returns:

  • (Array<Hash>)

80
81
82
# File 'lib/opto/group.rb', line 80

def to_a(with_errors: false, with_values: false)
  options.map {|opt| opt.to_h(with_errors: with_errors, with_value: with_values) }
end

#to_h(values_only: false, with_values: false, with_errors: false) ⇒ Hash

Convert a Group to a hash that has { option_name => option_value }

Returns:

  • (Hash)

86
87
88
89
90
91
92
# File 'lib/opto/group.rb', line 86

def to_h(values_only: false, with_values: false, with_errors: false)
  if values_only
    Hash[*options.flat_map {|opt| [opt.name, opt.type == 'group' ? opt.value.to_h(values_only: true) : opt.value]}]
  else
    Hash[*options.flat_map {|opt| [opt.name, opt.to_h(with_value: with_values, with_errors: with_errors).reject {|k,_| k==:name}]}]
  end
end

#valid?Boolean

Are all options valid? (Option value passes validation)

Returns:

  • (Boolean)

62
63
64
# File 'lib/opto/group.rb', line 62

def valid?
  options.all? {|o| o.valid? }
end

#value_of(option_name) ⇒ option_value, NilClass

Get a value of a member by option name

Parameters:

  • option_name (String)

Returns:

  • (option_value, NilClass)

135
136
137
138
# File 'lib/opto/group.rb', line 135

def value_of(option_name)
  opt = option(option_name)
  opt.nil? ? nil : opt.value
end