# Subroutines allow you to build reusable blocks of TML code that return some result back to # your main TML source. # # If you are able to make use of Subroutines to fill a role that Widgets don't already fill, # let me know so that I have a reason to keep this code around, because I'm considering removing # this from RTML. # class Rtml::Widgets::Subroutine < Rtml::Widget affects :document, :element entry_point :subroutine, :call, :subroutine? disable_subprocessing! shared :subroutines => HashWithIndifferentAccess def subroutine(name, options = { }, &block) #return document.subroutine(name, options, &block) if document != parent subroutines[name] = Rtml::HighLevel::Subroutine.new(name, parent, options, &block) end def subroutine?(name) name = name.to_s if name.kind_of?(Symbol) return true if subroutines.key?(name) return true if parent != document && parent.parent.subroutine?(name) false end def call(name, arguments = {}) raise Rtml::Errors::ProcessingError, "Can only call a subroutine from within a screen" unless parent.name == 'screen' #return document.call(name, arguments) if document != parent name = name.to_s if name.kind_of?(Symbol) doc = document p = parent document.string :rtml_sub_return_val while p == doc || p.respond_to?(:parent) #unless p.subroutines # raise "No subroutines hash for #{p.inspect}" #end if p.subroutines && p.subroutines.key?(name) return_value = p.subroutines[name].call(parent, arguments) begin parent.set :rtml_sub_return_val => return_value rescue ArgumentError parent.set :rtml_sub_return_val => '' end return parent.terminal_variables[:rtml_sub_return_val] end raise NoMethodError, "Subroutine does not exist: #{name}" if p == doc raise Rtml::Errors::ProcessingError, "Parent of #{p.inspect} is nil" unless p.parent p = p.parent end raise Rtml::Errors::ProcessingError, "Found a parent that is not a parent...? (this shouldn't happen)" end end