Module: Rtml::Widgets

Included in:
Test::Simulator
Defined in:
lib/rtml/widgets.rb

Overview

This module makes sure that all Widgets that can be found in Rtml.configuration.widget_paths have been loaded, and then registers Widget functionality with whatever class included Rtml::Widgets. Note that while merely including this module does allow your class to support Widgets, the Widget itself must declare that it is meant to affect your object.

You can interface with existing Widgets (assuming they support your class at a more fundamental level) by defining a self.name method which returns the name of one of the elements the Widget in question affects. This definition must appear before the inclusion of Rtml::Widgets.

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.basesObject (readonly)

A list of all objects that have included Rtml::Widgets, marking them as compatible with Widgets.



14
15
16
# File 'lib/rtml/widgets.rb', line 14

def bases
  @bases
end

Class Method Details

.add_proxies_to_base(base) ⇒ Object

Mixes the various proxy methods into the specified base.



69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/rtml/widgets.rb', line 69

def add_proxies_to_base(base)
  target_name = base.respond_to?(:name) ? (base.name || base.class.name).underscore.sub(/^.*\//, '') : nil
  (@widget_mapping ||= {}).each do |key, mixin|
    klass = base
    if base.kind_of?(ActiveRecord::Base) || base.kind_of?(Rtml::DocumentModelObject)
      klass = class << base; self; end
    end

    if klass.respond_to?(:name) && key == target_name
      klass.send(:include, mixin)
    end
  end
end

.affecting(target) ⇒ Object

Returns all Widgets which affect the specified target.



37
38
39
40
# File 'lib/rtml/widgets.rb', line 37

def affecting(target)
  target = (target.respond_to?(:name) ? target.name : target.to_s).underscore
  mapping(target).proxied_widgets
end

.create_widgets_array(base) ⇒ Object



124
125
126
127
128
129
# File 'lib/rtml/widgets.rb', line 124

def create_widgets_array(base)
  base.instance_eval do
    class_inheritable_array :class_widgets
    read_inheritable_attribute(:class_widgets) || write_inheritable_attribute(:class_widgets, [])
  end
end

.included(base) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/rtml/widgets.rb', line 43

def included(base)
  @bases ||= []
  @bases << base

  create_widgets_array(base)
  base.send(:include, Rtml::WidgetCore::WidgetAccessorInstanceMethods)
  base.send(:extend,  Rtml::WidgetCore::WidgetAccessorClassMethods)
  load_widgets
  add_proxies_to_base(base)

  base.class_eval do
    if defined?(initialize)
      def initialize_with_widgets(*args, &block)
        initialize_without_widgets(*args, &block)
        Rtml::Widgets.add_proxies_to_base(self)
      end
      alias_method_chain :initialize, :widgets
    else
      def initialize
        Rtml::Widgets.add_proxies_to_base(self)
      end
    end
  end
end

.load_widget!(file) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/rtml/widgets.rb', line 110

def load_widget!(file)
  if Rtml.configuration.widget_logging_enabled
    begin
      result = require_dependency(file)
      Rails.logger.debug "Loading Widget: #{file} (#{result})"
    rescue
      Rails.logger.debug "Loading Widget: #{file} (#{$!.message})"
      raise $!
    end
  else
    require_dependency file
  end
end

.load_widgets(load_path = nil) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/rtml/widgets.rb', line 83

def load_widgets(load_path = nil)
  if load_path.nil?
    load_widgets(File.join(Rtml.root, 'builtin/widgets'))

    Rtml.configuration.widget_paths.each do |lp|
      if defined?(Rails) && defined?(Rails.root)
        lp = File.join(Rails.root, lp) unless lp =~ /^#{Regexp::escape Rails.root}/ || lp =~ /^C\:/ || lp =~ /\//
        load_widgets(lp)
      else
        load_widgets(lp)
      end
    end
  else
    if File.file?(load_path)
      load_widget!(load_path)
    else
      if Rtml.configuration.widget_logging_enabled
        Rails.logger.debug "Searching for Widgets in '#{load_path}/**/*.rb'..."
      end
      Dir.glob(File.join(load_path, "**/*.rb")).each do |fi|
        next if fi =~ /\.svn/ or File.directory?(fi)
        load_widget!(fi)
      end
    end
  end
end

.mapping(key) ⇒ Object

The Widget mapping is a hash whose keys are symbols and whose values are instances of Module. The symbols represent either RTML models or TML tag names, while the Modules represent the proxy from the representation’s class into the Widget itself. This way, the Module can be mixed-in with the target, and Widgets added after the fact can simply add methods to the mixed-in Module. These methods are automatically added to the target class by Ruby. It’s a really fancy version of doing something like this:

mixin = Module.new
mixin.send(:define_method, :say_hi) { puts 'hello' }
class Target; end
Target.send(:include, mixin)
mixin.send(:define_method, :say_bye) { puts 'goodbye' } # notice this happens AFTER it's mixed in!

target_instance = Target.new
target_instance.say_hi        # => hello
target_instance.say_bye       # => goodbye


30
31
32
33
34
# File 'lib/rtml/widgets.rb', line 30

def mapping(key)
  name = (key.respond_to?(:name) ? key.name : key.to_s).underscore
  @widget_mapping ||= {}
  @widget_mapping[name] ||= Rtml::WidgetCore::WidgetProxy.new
end