Module: Command::DSL::Argument

Included in:
AlternatingArgument, ArgumentDecorator, CommandDefinition
Defined in:
lib/command-set/dsl.rb

Overview

The meta-programmatic machinery to create arguments quickly. Includes methods such that argument classes can register themselves into the DSL. Much of this module is unfortunately obtuse - it’s designed so that argument types can be easily extended, which makes the actual DSL trickier to document.

Ultimately, arguments are governed by their basic type (which descends from Argument) and the ArgumentDecorator objects that wrap it.

Within a Command#setup or CommandSet#command block, you can make decorator and argument calls like:

optional.named.string_argument :person, "A Person"

Which will create a StringArgument and wrap it in the NamedArgument and OptionalArgument ArgumentDecorators. This sounds confusing, but the upshot is that the person argument can be omitted, but if it’s included, it must be preceded with the argument’s name: “person” like so:

> command person judson

Which will assign “judson” to the person argument for the command.

:include: doc/argumentDSL

Defined Under Namespace

Classes: SubjectDeferral

Constant Summary collapse

@@decorator_map =
{}
@@argmap =
{}
@@shorthand_map =
{}

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.argument_typemapObject

:nodoc:



273
274
275
# File 'lib/command-set/dsl.rb', line 273

def self.argument_typemap #:nodoc:
  @@argmap
end

.documentObject

Generates rdoc ready documentation of the decorator and argument methods created by #register calls. Output is included in this module’s documentation. Also useful if you want to document your own argument class’ contributions. Try something like:

> ruby -r"lib/command-set/arguments.rb" -e "puts Command::DSL::Argument::document"


228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/command-set/dsl.rb', line 228

def self.document
  docs = <<-EOD 
  There are two kinds of methods available for #{self.name}.  
  First there are decorators.  They mark up arguments with extra
  meaning, like being optional.  The second are actual argument
  creation calls, which are shorthand for something like 
    argument FiddlyArgument {}

  In general, you'll use these something like

    decorator.decorator.shorthand_argument "name"

  For instance

    named.optional.file_argument "config"

  Decorator methods, and the classes they add:

  EOD

  @@decorator_map.each_pair do |method, klass|
    docs += "+#{method}+:: #{klass.name.sub("Command::","")}\n"
  end

  docs += <<-EOD

  The shorthand argument methods are:

  EOD

  @@shorthand_map.to_a.sort.each do |method, klass|
    docs += "+#{method}+:: #{klass.name.sub("Command::","")}\n"
  end

  docs += <<-EOD

  Don't forget about #alternating_argument and #argument itself!
  EOD

  indent = /^\s+/.match(docs)[0]
  docs.gsub!(/^#{indent}/, "")

  return docs
end

.register_argument(klass, shorthand, type = nil) ⇒ Object

The Argument#register method calls back to this, which creates methods like funky_argument that are responsible for embedding the actual arguments in the Commands they’re declared for.



211
212
213
214
215
216
217
218
219
220
# File 'lib/command-set/dsl.rb', line 211

def self.register_argument(klass, shorthand, type=nil)
  unless type.nil? or not Class === type or @@argmap.has_key?(type)
    @@argmap[type]=klass
  end

  method_name = shorthand + "_argument"
  @@shorthand_map[method_name] = klass

  alias_method method_name, :special_argument
end

.register_decorator(klass, method) ⇒ Object

The ArgumentDecorator#register method calls back to this, so that decorators can quickly register a method to wrap an argument with themselves.



201
202
203
204
# File 'lib/command-set/dsl.rb', line 201

def self.register_decorator(klass, method)
  @@decorator_map[method] = klass
  alias_method method, :create_decorator
end

Instance Method Details

#alternating_argument(name = nil, &block) ⇒ Object Also known as: alternating

Sugar for creating an alternating argument. Basically, an alternating argument is a series of arguments, any of which could be set. They either need to be of distinct types, or use named to distinguish between them.



331
332
333
334
# File 'lib/command-set/dsl.rb', line 331

def alternating_argument(name=nil, &block)
  arg = AlternatingArgument.new(self, &block)
  arg.name(name)
end

#argument(arg, *values, &get_values) ⇒ Object

The basic argument definition. If arg is an Argument object, it’ll be used - which means that you can explicitly create and argument and embed it. Otherwise, the values of values or get_values will be used to create the argument



300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
# File 'lib/command-set/dsl.rb', line 300

def argument(arg, *values, &get_values)
  name = nil
  argument = nil
  if(::Command::Argument === arg)
    name = arg.name
    argument = arg
  elsif(Class === arg and ::Command::Argument > arg)
    argument = arg.new(values[0], get_values||values[1])
  else
    name = arg
    argument = create(name, get_values||values.first)
  end

  return self.embed_argument(argument)
end

#create(name, basis) ⇒ Object

The method used to instantiate arguments based on their values. Searches all registered Argument classes, from children up, until one admits to being able to create arguments based on the value.

Raises:

  • (TypeError)


341
342
343
344
345
346
347
348
349
# File 'lib/command-set/dsl.rb', line 341

def create(name, basis)
  @@argmap.keys.sort{|r,l|(r>l)?1:-1}.each do |type| #Check child classes first
    if type === basis
      return @@argmap[type].new(name, basis)
    end
  end
  raise TypeError, "Don't know how to base an argument " +
                   "on #{basis.class}"
end

#create_decorator(&block) ⇒ Object

When an ArgumentDecorator calls self.register, this method is aliased with the name the decorator passes It takes care of instantiating the decorator such that it’s available to decorate the eventual argument.

Don’t look to closely at the source. It does bad things.



282
283
284
285
# File 'lib/command-set/dsl.rb', line 282

def create_decorator(&block)
  me = /:in `([^']*)/.match(caller(0)[0])[1]
  return ArgumentDecorator.new(self, @@decorator_map[me], &block) 
end

#named_optionalsObject

:nodoc:

Raises:

  • (NotImplementedException)


351
352
353
# File 'lib/command-set/dsl.rb', line 351

def named_optionals #:nodoc:
  raise NotImplementedException
end

#special_argument(name, values = nil, &get_values) ⇒ Object

This method functions analogously to create_decorator, except it works for arguments, not decorators. It’s worth looking at as the call signature for all funky_argument style calls.



290
291
292
293
294
# File 'lib/command-set/dsl.rb', line 290

def special_argument(name, values=nil, &get_values)
  me = /:in `([^']*)/.match(caller(0)[0])[1]
  argument = @@shorthand_map[me].new(name, get_values||values)
  return self.embed_argument(argument)
end

#subjectObject

Returns a SubjectDeferral Ultimately, this allows you to reference and base an argument on a value in the subject. Check this out:

number_argument :which_little_pig subject.pigs {|pigs| 1..pigs.length}

When that argument is evaluated, the pigs (is_a? Array) field of the subject will get turned into a range: from 1 to it’s length.



323
324
325
# File 'lib/command-set/dsl.rb', line 323

def subject
  return SubjectDeferral.new
end