Class: Rtml::Widget

Inherits:
Object
  • Object
show all
Extended by:
Rtml::WidgetCore::ClassMethods
Includes:
Assigns
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 . . .]

Direct Known Subclasses

Test::SimulatorPostProcessors::Base

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

Methods included from Assigns

#assignment_names, #assigns

Constructor Details

#initialize(parent) ⇒ Widget

Returns a new instance of Widget.



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/rtml/widget.rb', line 109

def initialize(parent)
  @parent = parent
  set_source_type!
  parent.widget_instances << self

  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

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object

Any method other than one of this widget’s entry points will be delegated into #parent. The parent’s methods are not known until runtime, and it’s extraordinarily slow to generate delegation for those methods on the fly. Method_missing is the happy middle ground.

Raises:

  • (NoMethodError)


98
99
100
101
102
103
# File 'lib/rtml/widget.rb', line 98

def method_missing(name, *args, &block)
  name = name.to_s unless name.kind_of?(String)
  return parent.send(name, *args, &block) unless entry_points.include?(name) || !parent.respond_to?(name)
  # FIXME: Why does super raise an ArgumentError("no id given")?
  raise NoMethodError, "Method missing: #{name}"
end

Instance Attribute Details

#parentObject (readonly)

Returns the value of attribute parent.



74
75
76
# File 'lib/rtml/widget.rb', line 74

def parent
  @parent
end

#source_typeObject (readonly) Also known as: parent_type

Returns the value of attribute source_type.



75
76
77
# File 'lib/rtml/widget.rb', line 75

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.



147
148
149
# File 'lib/rtml/widget.rb', line 147

def disable_subprocessing!
  @disable_subprocessing = true
end

#documentObject



86
87
88
# File 'lib/rtml/widget.rb', line 86

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!



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

def enable_subprocessing!
  @disable_subprocessing = false
end

#respond_to?(*a, &b) ⇒ Boolean

Returns:

  • (Boolean)


105
106
107
# File 'lib/rtml/widget.rb', line 105

def respond_to?(*a, &b)
  super || parent.respond_to?(*a, &b)
end

#subprocessing_disabled?Boolean Also known as: disable_subprocessing?

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

Returns:

  • (Boolean)


128
129
130
131
# File 'lib/rtml/widget.rb', line 128

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

#validate_parent(*options) ⇒ Object



78
79
80
81
82
83
84
# File 'lib/rtml/widget.rb', line 78

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

#widget_idObject

A guaranteed unique ID for this Widget.



91
92
93
# File 'lib/rtml/widget.rb', line 91

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