Module: Rtml::WidgetCore::ClassMethods

Included in:
Rtml::Widget
Defined in:
lib/rtml/widget_core/class_methods.rb

Constant Summary collapse

@@gui_enabled_widgets =
{}

Instance Method Summary collapse

Instance Method Details

#add_entry_point(entry_point) ⇒ Object

Adds the specified entry point to this Widget’s proxy module.



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
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
180
181
# File 'lib/rtml/widget_core/class_methods.rb', line 133

def add_entry_point(entry_point)
  # This validation doesn't work because it's not this proxy module, it's those of the OTHER Widgets
  # that should be checked. Not sure of the best way to do that yet.
#    if proxy_module.public_instance_methods.include?(entry_point)
#      raise Rtml::Errors::RulesViolationError,
#            "Widget entry point #{entry_point} cannot be defined because it already exists!"
#    end
  #entry_point = entry_point.to_sym unless entry_point.is_a?(Symbol)
  entry_point = entry_point.to_s if entry_point.is_a?(Symbol)
  
  enter_from_hash = "#{entry_point}_from_hash"
  ['?','!'].each do |i|
    enter_from_hash = enter_from_hash.gsub(/#{Regexp::escape(i)}/, '') + i if enter_from_hash[i]
  end

  line = __LINE__ + 2
  code = <<-end_code
    def #{entry_point}(*args, &block)               # def screen(*args, &block)
      widget = #{self.name}.new(self)               #   widget = Rtml::Widgets::Screens.new(self)
      r = widget.#{entry_point}(*args, &block)      #   r = widget.screen(*args, &block)

      unless widget.disable_subprocessing? || !block_given?
        unless r.respond_to?(:process)
          raise Rtml::Errors::SubprocessingNotSupported, "Return value \#{r} does not support subprocessing"
        end
        r.process &block
      end
      r
    rescue ArgumentError => ae
      if ae.backtrace[0] =~ /#{Regexp::escape entry_point}/
        raise ArgumentError, ae.message, caller
      else raise ae
      end
    end                                             # end

    # Calls the entry point after reformatting the arguments in hash to fit the entry point's requirements
    # per +Rtml::WidgetCore::GuiConfiguration#construct_arguments+
    #
    # This is primarily for interfacing with the RTML GUI.
    #
    def #{enter_from_hash}(hash, &block)
      arguments = #{self}.gui_configuration.construct_arguments(hash || {})
      self.#{entry_point} *arguments, &block
    end
  end_code
  proxy_module.class_eval code, __FILE__, line
  reinclude_proxy_module
  entry_point
end

#affects(*targets) ⇒ Object

Specifies the targets that this Widget will affect. A target can be a name of a model or the name of a TML tag, which matches that model’s “name” attribute.

Examples:

affects :document, :element, :property # names of models
affects :tml, :head, :screen           # names of TML tags


95
96
97
98
99
100
101
102
103
104
105
# File 'lib/rtml/widget_core/class_methods.rb', line 95

def affects(*targets)
  targets.flatten.each do |target|
    target = target.to_s unless target.kind_of?(String)
    unless self.targets.include? target
      self.targets << target
      map = Rtml::Widgets.mapping(target)
      map.proxied_widgets << self
      map.imbue(proxy_module)
    end
  end
end

#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.

If you want to disable subprocessing only under certain conditions, see the instance method of the same name.



73
74
75
# File 'lib/rtml/widget_core/class_methods.rb', line 73

def disable_subprocessing!
  @disable_subprocessing = true
end

#enable_subprocessing!Object

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



78
79
80
# File 'lib/rtml/widget_core/class_methods.rb', line 78

def enable_subprocessing!
  @disable_subprocessing = false
end

#entry_point(*names) ⇒ Object

Specifies entry points, which are names of methods that can be called from the targets to invoke this Widget.

Examples:

entry_point :screen


123
124
125
126
127
128
129
130
# File 'lib/rtml/widget_core/class_methods.rb', line 123

def entry_point(*names)
  names.each do |name|
    #name = name.to_sym unless name.kind_of?(Symbol)
    unless entry_points.include?(name)
      entry_points << add_entry_point(name)
    end
  end
end

#gui {|gui_configuration| ... } ⇒ Object

Yields this Widget’s GUI configuration to the supplied block, allowing you to set up your Widget to be accessible from the RTML Application Builder. Note that if this method is never called, your Widget will not be available to the GUI.

Yields:



22
23
24
# File 'lib/rtml/widget_core/class_methods.rb', line 22

def gui
  yield(gui_configuration)
end

#gui_configurationObject

Returns the Rtml::WidgetCore::GuiConfiguration instance for this Widget. Shorthand for:

widget.gui_enabled_widgets[widget]


29
30
31
# File 'lib/rtml/widget_core/class_methods.rb', line 29

def gui_configuration
  gui_enabled_widgets[self] ||= Rtml::WidgetCore::GuiConfiguration.new(self)
end

#gui_enabled_widgetsObject

Returns the array of Widgets that have called the #gui method, thereby marking themselves as accessible to the RTML Application Builder.



35
36
37
# File 'lib/rtml/widget_core/class_methods.rb', line 35

def gui_enabled_widgets
  @@gui_enabled_widgets
end

#proxy_moduleObject



4
5
6
7
8
9
10
11
12
13
14
15
16
17
# File 'lib/rtml/widget_core/class_methods.rb', line 4

def proxy_module
  return @proxy_module if @proxy_module
  @proxy_module = Module.new
  @proxy_module.instance_variable_set("@shared_variables", shared_variables)
  @proxy_module.instance_eval do
    def included(base)
      @shared_variables.each do |sv|
        base.send(:attr_accessor, sv[:name])
      end
    end
  end

  @proxy_module
end

#reinclude_proxy_moduleObject

Goes through each of the targets of this Widget, looks up its mapping in Rtml::Widgets.mapping, and calls proxy_module.append_features(mapping) for each of those mappings.



110
111
112
113
114
115
116
# File 'lib/rtml/widget_core/class_methods.rb', line 110

def reinclude_proxy_module
  targets.each do |target|
    Rtml::Widgets.mapping(target).imbue(proxy_module)
  end
  # FIXME: Um... Maybe this is fine, but it seems out of place.
  Rtml::Widgets.bases.each { |base| Rtml::Widgets.add_proxies_to_base(base) }
end

#shared(*names) ⇒ Object

Creates a “shared” variable for the parent object with the specified default value, if any. This is much like a class variable, except that it is unique to the parent object in question. Multiple calls to a Widget’s entry point will result in multiple Widgets being instantiated. If you use an instance variable to hold data, then that instance variable will be different for every entry point called. However, sometimes you need to share data across multiple instances of the same Widget, but not across all instances of the same Widget. For instance, your Widget may want to track references to variables in an individual Screen, but not across multiple Screens. To accomplish this, you essentially need an instance variable for the Screen. The “shared” method manages these variables for you.

Examples:

shared :tml_variables
shared :variable_definitions, :variable_declarations
shared :tml_variables => []                          # initializes #tml_variables to [].dup


52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/rtml/widget_core/class_methods.rb', line 52

def shared(*names)
  names.each do |name|
    if name.kind_of? Hash
      value = name.values.first
      name = name.keys.first.to_s
      shared_variables << { :name => name, :default_value => value }
    else
      name = name.to_s
      shared_variables << { :name => name, :default_value => nil }
    end
    delegate name, "#{name}=", :to => :parent
  end
  reinclude_proxy_module
end

#subprocessing_disabled?Boolean Also known as: disable_subprocessing?

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

Returns:

  • (Boolean)


83
84
85
# File 'lib/rtml/widget_core/class_methods.rb', line 83

def subprocessing_disabled?
  @disable_subprocessing ||= false
end

#target?(base) ⇒ Boolean

Returns true if the specified class is a valid target of this Widget

Returns:

  • (Boolean)


184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/rtml/widget_core/class_methods.rb', line 184

def target?(base)
  if base.respond_to?(:name)
    name = base.name.underscore.sub(/^.*\//, '')
    targets.each do |target|
      if base.kind_of?(ActiveRecord::Base) || base.kind_of?(Rtml::DocumentModelObject) # it's an instance, so we should check the tag name, not the class name
        return true if target == base.name
      else
        return true if target == name
      end
    end
  end
  false
end