Class: Rtml::Widget

Inherits:
Object
  • Object
show all
Extended by:
Rtml::WidgetCore::ClassMethods
Defined in:
lib/rtml/widget.rb

Overview

The Widget is the driving force behind RubyTML. It is interaction with Widgets of all shapes and sizes that produces a document model and, finally, the TML document itself. A Widget is so named because it is a generic class that can be made to encapsulate any desired functionality. The Rtml::Widget base class takes care of interfacing content generation code with the RTML project as a whole.

If you’ve done any RTML programming at all, you’ve been using Widgets. Does the following code look familiar?

screen :idle, :next => :main, :timeout => 3 do
  display
end

Even core functionality such as the “screen” method is traced back to a Widget – in this case, Rtml::Widgets::Screens.

Since interfacing with the various components of RTML is handled by the base class, writing a Widget is easy:

class Rtml::Widgets::CardParser < Rtml::Widget
  affects :screen
  entry_point :card

  def card(options = {})
    raise ":parser must be provided" unless options[:parser]
    parent.build :card, :parser => options[:parser], :parser_params => (options[:params] || 'read_data')
  end
end

When invoked from a Screen, this code will produce a TML card parser element:

screen . . . do
  card :parser => :mag   #=> <card parser='mag' params='read_data' />
end

If you are just interested in using the Widgets, you are encouraged to read the documentation for the various Widgets themselves. If you find that you need to program a new Widget in order to address some missing functionality, you can generate one easily with the command line generator:

ruby script/generate widget my_widget [entry_point1 entry_point2 . . .]

Constant Summary collapse

RDOC_ACCESSORS =

These are the accessors that RDoc uses to define what a particular RTML-specific attribute maps to.

There are 3 kinds of accessors:

  • Shared variable

    • These are used to create variables that are different across parent objects, but which are shared between multiple Widgets (whether totally separate, or instances of the same) on the same instantiated parent. It’s a little complicated, but it’s critical in (for example) tracking TML variable definitions.

  • Valid parent

    • These are the names of TML elements (or “document” for document-level Widgets) that are allowed to instantiate the Widget in question by calling its entry points.

  • Entry point

    • These are instance methods defined by the Widget which are proxied into potential parent objects. Calling an entry point results in the configuration and eventual instantiation of the Widget which declared the entry point.

{
  :shared => 'shared variable',
  :affects => 'valid parent',
  :entry_point => "entry point",
}
@@widget_id_tracker =
0

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(parent) ⇒ Widget

Returns a new instance of Widget.



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/rtml/widget.rb', line 86

def initialize(parent)
  @parent = parent
  set_source_type!
  parent.widget_instances << self
  # proxy parent methods into parent, unless they exist for widget already
  singleton_class = (class << self; self; end)
  (@parent.public_methods - self.public_methods).each do |proxy_method|
    # don't delegate entry points -- this addresses the infinite loop issue in which calling a method that's been
    # defined as an entry point but hasn't been created in the Widget itself would recurse back into the parent
    # object forever.
    unless entry_points.include? proxy_method
      singleton_class.send(:delegate, proxy_method, :to => :parent)
    end
  end


  self.class.shared_variables.each do |sv|
    unless @parent.instance_variable_get("@#{sv[:name]}")
      if sv[:default_value]
        if sv[:default_value].kind_of?(Class)
          @parent.instance_variable_set("@#{sv[:name]}", sv[:default_value].new)
        else
          @parent.instance_variable_set("@#{sv[:name]}", sv[:default_value].dup)
        end
      end
    end
  end
end

Instance Attribute Details

#parentObject (readonly)

Returns the value of attribute parent.



66
67
68
# File 'lib/rtml/widget.rb', line 66

def parent
  @parent
end

#source_typeObject (readonly) Also known as: parent_type

Returns the value of attribute source_type.



67
68
69
# File 'lib/rtml/widget.rb', line 67

def source_type
  @source_type
end

Instance Method Details

#disable_subprocessing!Object

By default, if a Widget’s entry point is called with a block argument, it will be passed into the #process method of the entry point’s return value. This is called subprocessing – that is, processing the element to be returned at a lower level. This method disables subprocessing and its related assertions. It’s useful, for instance, if you want to manually control how or when the block argument is processed, or if you want to ignore it entirely.

There is a class method of the same name that has the same effect for the entire class; this instance method can disable subprocessing for particular instances, and is useful if you only want subprocessing under certain conditions.



135
136
137
# File 'lib/rtml/widget.rb', line 135

def disable_subprocessing!
  @disable_subprocessing = true
end

#documentObject



77
78
79
# File 'lib/rtml/widget.rb', line 77

def document
  @document ||= (parent.kind_of?(Rtml::Document) || !parent.respond_to?(:document) ? parent : parent.document)
end

#enable_subprocessing!Object

Use this to enable subprocessing after it has already been disabled. See #disable_subprocessing!



123
124
125
# File 'lib/rtml/widget.rb', line 123

def enable_subprocessing!
  @disable_subprocessing = false
end

#subprocessing_disabled?Boolean Also known as: disable_subprocessing?

Returns true if subprocessing has been disabled. See also #disable_subprocessing!

Returns:

  • (Boolean)


116
117
118
119
# File 'lib/rtml/widget.rb', line 116

def subprocessing_disabled?
  @disable_subprocessing = self.class.disable_subprocessing? unless defined?(@disable_subprocessing)
  @disable_subprocessing
end

#validate_parent(*options) ⇒ Object



70
71
72
73
74
75
# File 'lib/rtml/widget.rb', line 70

def validate_parent(*options)
  options = options.flatten.collect { |o| o.kind_of?(String) ? o : o.to_s }
  unless options.include?(parent.name)
    raise ArgumentError, "Expected parent to be one of #{options.to_sentence(:language => :en)}; found #{parent.name}"
  end
end

#widget_idObject

A guaranteed unique ID for this Widget.



82
83
84
# File 'lib/rtml/widget.rb', line 82

def widget_id
  @widget_id ||= (@@widget_id_tracker += 1)
end