Class: AppKernel::Function::Options

Inherits:
Object
  • Object
show all
Defined in:
lib/appkernel/curry.rb,
lib/appkernel/function.rb
more...

Defined Under Namespace

Classes: Option

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeOptions

Returns a new instance of Options.

[View source]

143
144
145
146
147
148
149
150
# File 'lib/appkernel/function.rb', line 143

def initialize
  @options = {}
  @indexed = []
  @required = []
  @defaults = []
  @presets = {}
  @greedy = nil
end

Instance Attribute Details

#optionsObject (readonly)

Returns the value of attribute options.


141
142
143
# File 'lib/appkernel/function.rb', line 141

def options
  @options
end

Instance Method Details

#add(name, modifiers) ⇒ Object

[View source]

152
153
154
# File 'lib/appkernel/function.rb', line 152

def add(name, modifiers)
  ingest Option.new(name, modifiers)
end

#canonicalize(args, errors, augment = true) ⇒ Object

first, exctract all hash options if we find one we love, use it otherwise, if there’s a slurpy option, throw it on the pile otherwise, it’s an error.

[View source]

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
217
218
# File 'lib/appkernel/function.rb', line 183

def canonicalize(args, errors, augment = true)
  indexed = @indexed.compact
  positionals, parameters, rest = comb(args)
  unless @greedy
    errors.add(nil,"too many arguments (#{positionals.length} for #{indexed.length})") if positionals.length > indexed.length
    for hash in rest
      for k,v in hash
        errors.add(k, "unknown option '#{k}'")
      end
    end
    return unless errors.empty?
  end
  @presets.dup.tap do |canonical|
    canonical[@greedy.name] = rest if @greedy
    for name,value in parameters
      canonical[name] = @options[name].resolve(value)
    end          
    positionals.length.times do |i|          
      if opt = indexed[i]
        canonical[opt.name] = opt.resolve(positionals[i])
      end
    end
    if @greedy
      canonical[@greedy.name] = @greedy.resolve(rest)
    end          
    if augment
      for k in @defaults
        canonical[k] = @options[k].default unless canonical[k]
      end
      canonical.reject! {|k,v| v.nil? || (@options[k] && @options[k].list? && v.empty?)}
      for k in @required - canonical.keys
        errors.add(k, "missing required option '#{k}'")
      end
    end          
  end      
end

#comb(args) ⇒ Object

[View source]

220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/appkernel/function.rb', line 220

def comb(args)
  positionals = []
  parameters = {}
  rest_parameters = {}
  rest = []
  index = @indexed.compact.length
  for arg in args
    if Hash === arg
      for name,value in arg
        key = name.to_sym
        if opt = @options[key]
          parameters[opt.name] = value
        else
          rest_parameters[key] = value
        end
      end
    elsif index > 0
      index -= 1
      positionals << arg
    else
      rest << arg
    end
  end
  rest << rest_parameters unless rest_parameters.empty?
  return positionals, parameters, rest
end

#curry(parent, params) ⇒ Object

Raises:

  • (ArgumentError)
[View source]

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/appkernel/curry.rb', line 11

def curry(parent, params)
  errors = Errors.new
  presets = parent.canonicalize([params], errors, false)
  raise ArgumentError, errors.all.join('; ') unless errors.empty?
  @presets.merge! presets
  applied, unapplied = parent.options.values.partition {|o| @presets.has_key?(o.name)}
  unapplied.each do |option|
    ingest option
  end
  applied.each do |option|
    if option.required? && @presets[option.name].nil?
      raise ArgumentError, "required option '#{option.name}' may not be nil"
    end
  end
end

#ingest(o) ⇒ Object

Raises:

[View source]

156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/appkernel/function.rb', line 156

def ingest(o)        
  @options[o.name] = o
  @indexed[o.index] = o if o.index
  @required << o.name if o.required?
  @defaults << o.name if o.default?        
  if o.default? && o.type
    if Enumerable === o.type 
      if not o.type.detect {|t| o.default.kind_of?(t)}
        raise IllegalOptionError, "default value #{o.default.inspect} for option '#{o.name}' is not in #{o.type.inspect}"
      end            
    elsif not o.default.kind_of?(o.type)
      raise IllegalOptionError, "default value #{o.default.inspect} for option '#{o.name}' is not a #{o.type}"
    end
  end
  if o.greedy?
    raise IllegalOptionError, "a function may not have more than one greedy option. has (#{@greedy.name}, #{o.name})" if @greedy
    @greedy = o
  end
  raise IllegalOptionError, "a greedy option may not have an index" if o.greedy? && o.index
end