Class: Rap::DeclarationTask
- Inherits:
-
Tap::Task
- Object
- Tap::Task
- Rap::DeclarationTask
- Extended by:
- Declarations
- Defined in:
- lib/rap/declaration_task.rb,
lib/rap/declarations.rb
Overview
DeclarationTasks are a special breed of Tap::Task designed to behave much like Rake tasks. As such, declaration tasks:
-
return nil and pass nil in workflows
-
only execute once
-
are effectively singletons (one instance per app)
-
allow for multiple actions
The DeclarationTask class partially includes Declarations so subclasses may directly declare tasks. A few alias acrobatics makes it so that ONLY Declarations#task is made available (desc cannot be used because Task classes already use that method for documentation, and namespace would be silly).
Weird? Yes, but it leads to this syntax:
# [Rapfile]
# class Subclass < Rap::DeclarationTask
# def helper(); "help"; end
# end
#
# # ::desc a help task
# Subclass.task(:help) {|task, args| puts "got #{task.helper}"}
% rap help
got help
Class Attribute Summary collapse
-
.actions ⇒ Object
An array of actions (blocks) associated with this class.
-
.arg_names ⇒ Object
The argument names pulled from a task declaration.
Instance Attribute Summary collapse
-
#args ⇒ Object
The arguments assigned to self during call.
-
#result ⇒ Object
readonly
The result of self, set by call.
Class Method Summary collapse
-
.args ⇒ Object
Returns a Lazydoc::Arguments constructed from arg_names.
-
.instantiate(argh = {}, app = Tap::App.instance) ⇒ Object
Instantiates the instance of self for app and reconfigures it using argh.
-
.subclass(const_name, configs = {}, dependencies = []) ⇒ Object
Looks up or creates the DeclarationTask subclass specified by const_name and adds the configs and dependencies.
Instance Method Summary collapse
-
#call(*args) ⇒ Object
Conditional call to the super call; only calls once.
-
#initialize(config = {}, app = Tap::App.instance) ⇒ DeclarationTask
constructor
A new instance of DeclarationTask.
-
#process(*inputs) ⇒ Object
Collects the inputs into an OpenStruct according to the class arg_names, and calls each class action in turn.
-
#reset ⇒ Object
Resets self so call will call again.
-
#resolved? ⇒ Boolean
Returns true if already resolved by call.
Methods included from Declarations
app, app=, current_desc, current_namespace, desc, env, env=, instance, namespace, task
Methods included from Utils
Constructor Details
#initialize(config = {}, app = Tap::App.instance) ⇒ DeclarationTask
Returns a new instance of DeclarationTask.
142 143 144 145 146 147 |
# File 'lib/rap/declaration_task.rb', line 142 def initialize(config={}, app=Tap::App.instance) super @resolved = false @result = nil @args = nil end |
Class Attribute Details
.actions ⇒ Object
An array of actions (blocks) associated with this class. Each of the actions is called during process, with the instance and any args passed to process organized into an OpenStruct.
44 45 46 |
# File 'lib/rap/declaration_task.rb', line 44 def actions @actions ||= [] end |
.arg_names ⇒ Object
The argument names pulled from a task declaration.
52 53 54 |
# File 'lib/rap/declaration_task.rb', line 52 def arg_names @arg_names ||= [] end |
Instance Attribute Details
#args ⇒ Object
The arguments assigned to self during call.
140 141 142 |
# File 'lib/rap/declaration_task.rb', line 140 def args @args end |
#result ⇒ Object (readonly)
The result of self, set by call.
137 138 139 |
# File 'lib/rap/declaration_task.rb', line 137 def result @result end |
Class Method Details
.args ⇒ Object
Returns a Lazydoc::Arguments constructed from arg_names.
57 58 59 60 61 |
# File 'lib/rap/declaration_task.rb', line 57 def args args = Lazydoc::Arguments.new arg_names.each {|name| args.arguments << name.to_s } args end |
.instantiate(argh = {}, app = Tap::App.instance) ⇒ Object
Instantiates the instance of self for app and reconfigures it using argh. Configurations are set, the task name is set, and the arguments are stored on the instance. The arguments are returned as normal in the [instance, args] result.
These atypical behaviors handle various situations on the command line. Setting the args this way, for example, allows arguments to be specified on dependency tasks:
# [Rapfile]
# Rap.task(:a, :obj) {|t, a| puts "A #{a.obj}"}
# Rap.task({:b => :a}, :obj) {|t, a| puts "B #{a.obj}"}
% rap b world -- a hello
A hello
B world
80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/rap/declaration_task.rb', line 80 def instantiate(argh={}, app=Tap::App.instance) config = argh[:config] config_file = argh[:config_file] instance = self.instance(app) instance.reconfigure(load_config(config_file)) if config_file instance.reconfigure(config) if config instance.args = argh[:args] [instance, instance.args] end |
.subclass(const_name, configs = {}, dependencies = []) ⇒ Object
Looks up or creates the DeclarationTask subclass specified by const_name and adds the configs and dependencies.
Configurations are always validated using the yaml transformation block (see Configurable::Validation).
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 133 |
# File 'lib/rap/declaration_task.rb', line 97 def subclass(const_name, configs={}, dependencies=[]) # lookup or generate the subclass subclass = Tap::Env::Constant.constantize(const_name.to_s) do |base, constants| subclass_const = constants.pop constants.inject(base) do |namespace, const| # nesting Task classes into other Task classes is required # for namespaces with the same name as a task namespace.const_set(const, Class.new(DeclarationTask)) end.const_set(subclass_const, Class.new(self)) end # check a correct class was found unless subclass.ancestors.include?(self) raise "not a #{self}: #{subclass}" end # append configuration (note that specifying a desc # prevents lazydoc registration of these lines) convert_to_yaml = Configurable::Validation.yaml configs.each_pair do |key, value| subclass.send(:config, key, value, :desc => "", &convert_to_yaml) end # add dependencies dependencies.each do |dependency| dependency_name = File.basename(dependency.to_s.underscore) # this suppresses 'method redefined' warnings if subclass.method_defined?(dependency_name) subclass.send(:undef_method, dependency_name) end subclass.send(:depends_on, dependency_name, dependency) end subclass end |
Instance Method Details
#call(*args) ⇒ Object
Conditional call to the super call; only calls once. Returns result.
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 |
# File 'lib/rap/declaration_task.rb', line 150 def call(*args) # Declaration tasks function as dependencies, but unlike normal # dependencies, they CAN take arguments from the command line. # Such arguments will be set as args, and be used to enque the # task. # # If the task executes from the queue first, args will be # provided to call and they should equal self.args. If the task # executes as a dependency first, call will not receive args and # in that case self.args will be used. # # This warns for cases that odd workflows can produce where the # args have been set and DIFFERENT args are used to enque the task. # In these cases always go with the pre-set args but warn the issue. self.args ||= args unless self.args == args if @resolved warn "warn: ignorning dependency task inputs #{args.inspect} (#{self})" else warn "warn: invoking dependency task with preset args #{self.args.inspect} and not inputs #{args.inspect} (#{self})" end end unless @resolved @resolved = true @result = super(*self.args) end result end |
#process(*inputs) ⇒ Object
Collects the inputs into an OpenStruct according to the class arg_names, and calls each class action in turn. This behavior echoes the behavior of Rake tasks.
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
# File 'lib/rap/declaration_task.rb', line 195 def process(*inputs) # collect inputs to make a rakish-args object args = {} self.class.arg_names.each do |arg_name| break if inputs.empty? args[arg_name] = inputs.shift end args = OpenStruct.new(args) # execute each block assciated with this task self.class.actions.each do |action| case action.arity when 0 then action.call() when 1 then action.call(self) else action.call(self, args) end end nil end |
#reset ⇒ Object
Resets self so call will call again. Also sets result to nil.
187 188 189 190 |
# File 'lib/rap/declaration_task.rb', line 187 def reset @resolved = false @result = nil end |
#resolved? ⇒ Boolean
Returns true if already resolved by call.
182 183 184 |
# File 'lib/rap/declaration_task.rb', line 182 def resolved? @resolved end |