Skip to content

swineherd making scripts autorun

Philip (flip) Kromer edited this page May 9, 2012 · 1 revision

swineherd/launcher -- making scripts auto-run and other metaprogramming notes

Some metaprogramming tips:

http://apidock.com/rails/Object/instance_exec


http://ruby.runpaint.org/methods#dynamic-definition

define_singleton_method(:call, *proc)


http://www.ruby-doc.org/core-1.9.3/Proc.html#method-i-curry

Documentation

DSL Handlers in YARD

class ClassAttributeHandler < YARD::Handlers::Ruby::AttributeHandler
  handles method_call(:cattr_accessor)
  namespace_only

  def process
    push_state(:scope => :class) { super }
  end
end

Exit handler

Kernel.at_exit

http://www.tutorialspoint.com/ruby/ruby_blocks.htm

BEGIN and END Blocks Every Ruby source file can declare blocks of code to be run as the file is being loaded (the BEGIN blocks) and after the program has finished executing (the END blocks).

BEGIN { begin block code }

END { end block code }

A program may include multiple BEGIN and END blocks. BEGIN blocks are executed in the order they are encountered. END blocks are executed in reverse order.

Begin / Exit Handlers

(from Read Ruby

A begin or exit handler registers code to be executed at the beginning or end, respectively, of a program.

BEGIN Block

A BEGIN block, as opposed to a begin statement, is executed at the very beginning of a program. It consists of the BEGIN keyword at the top-level of a program, followed by statements delimited by curly braces, and defines its own variable scope. If multiple BEGIN blocks are present, they are executed in the order encountered by the interpreter.

puts 1
BEGIN { puts 2 }
puts 3
# Output:
# 2
# 1
# 3

END Block

An END block, as opposed to the end keyword, is executed at the very end of a program. They consist of the END keyword followed by statements delimited by curly braces. Unlike BEGIN blocks, they share local variable scope with surrounding code. A further difference is that the execution of an END block is governed by surrounding constructs: if it appears in the body of a conditional, for instance, its execution is dependent on that conditional being true. However, even if enclosed in a looping construct, an END block is still only executed once.

puts 1
END { puts 2 }
puts 3
# Output:
# 1
# 3
# 2

Kernel.at_exit

An alternative to END blocks is Kernel.at_exit. It accepts a block argument which it registers to execute at the end of program execution. If called multiple times the blocks are executed in reverse chronological order.

at_exit { puts 1 }
puts 2
at_exit { puts 3 }
at_exit { puts 4 } if false
# Output:
# 2
# 3
# 1

method_added

An example, from Thor:

    # Everytime someone inherits from a Thor class, register the klass
    # and file into baseclass.
    def inherited(klass)
      Thor::Base.register_klass_file(klass)
      klass.instance_variable_set(:@no_tasks, false)
    end

    # Fire this callback whenever a method is added. Added methods are
    # tracked as tasks by invoking the create_task method.
    def method_added(meth)
      meth = meth.to_s

      if meth == "initialize"
        initialize_added
        return
      end

      # Return if it's not a public instance method
      return unless public_instance_methods.include?(meth) ||
                    public_instance_methods.include?(meth.to_sym)

      return if @no_tasks || !create_task(meth)

      is_thor_reserved_word?(meth, :task)
      Thor::Base.register_klass_file(self)
    end

Standalone Executables

You may want to make a script as an executable command. To do this with Wukong:

  • include the ruby shebang (#!) line.
  • require 'wukong/exe' in your script.
  • define your Wukong jobflow, named the same as the script; the .rb suffix is optional.

Example: destroy_nukes.rb

#!/usr/bin/env ruby
require 'wukong/exe'

Wukong.job(:destroy_nukes) do
  task(:reprogram, :description => "...")
end

Make the script executable:

chmod a+x destroy_nukes.rb

Now you can type:

destroy_nukes.rb ...

How it works

The wukong/exe lib defines a ruby