rtml 2.0.3 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +3 -0
- data/Manifest.txt +51 -13
- data/Rakefile +6 -1
- data/builtin/controllers/rtml_controller.rb +12 -1
- data/builtin/models/rtml/document.rb +24 -18
- data/builtin/models/rtml/document_model_object.rb +6 -0
- data/builtin/models/rtml/dom/collections/element_set.rb +6 -0
- data/builtin/models/rtml/dom/collections/property_set.rb +11 -0
- data/builtin/models/rtml/dom/element.rb +79 -27
- data/builtin/models/rtml/dom/frontend_element.rb +41 -20
- data/builtin/models/rtml/dom/property.rb +43 -26
- data/builtin/models/rtml/dom/screen_element.rb +13 -0
- data/builtin/widgets/document_variable_processing.rb +42 -18
- data/builtin/widgets/element_builder.rb +4 -4
- data/builtin/widgets/screen_variable_processing.rb +2 -2
- data/builtin/widgets/screen_variants.rb +31 -4
- data/builtin/widgets/screens.rb +13 -1
- data/builtin/widgets/static_content.rb +20 -6
- data/do_profile.rb +15 -0
- data/lib/extensions/action_controller/response.rb +0 -18
- data/lib/extensions/action_controller/routing/route_set.rb +28 -18
- data/lib/extensions/hpricot/doc.rb +3 -3
- data/lib/extensions/hpricot/elem.rb +3 -3
- data/lib/extensions/string.rb +2 -18
- data/lib/rtml.rb +0 -12
- data/lib/rtml/assigns.rb +32 -0
- data/lib/rtml/controller/document_generator.rb +9 -0
- data/lib/rtml/controller/render_helpers.rb +42 -18
- data/lib/rtml/controller/state.rb +2 -1
- data/lib/rtml/dependencies.rb +20 -15
- data/lib/rtml/dsl.rb +10 -10
- data/lib/rtml/environment.rb +13 -1
- data/lib/rtml/errors/application_error.rb +5 -0
- data/lib/rtml/errors/simulation_error.rb +4 -0
- data/lib/rtml/errors/variable_error.rb +5 -0
- data/lib/rtml/high_level/variable_manager.rb +11 -7
- data/lib/rtml/inherited_instance_variables.rb +8 -1
- data/lib/rtml/links.rb +17 -0
- data/lib/rtml/rules/dom_validation.rb +1 -0
- data/lib/rtml/test/builtin_variables.rb +33 -0
- data/lib/rtml/test/resemblance_test.rb +97 -0
- data/lib/rtml/test/screen.rb +126 -0
- data/lib/rtml/test/simulator.rb +240 -0
- data/lib/rtml/test/simulator_post_processors/base.rb +7 -0
- data/lib/rtml/test/simulator_post_processors/card_parsers.rb +32 -0
- data/lib/rtml/test/simulator_post_processors/receipt.rb +15 -0
- data/lib/rtml/test/simulator_post_processors/submit.rb +15 -0
- data/lib/rtml/test/spec.rb +14 -7
- data/lib/rtml/test/spec/matchers.rb +24 -0
- data/lib/rtml/test/tml_application.rb +331 -0
- data/lib/rtml/test/unit.rb +13 -0
- data/lib/rtml/test/variable_scope.rb +146 -0
- data/lib/rtml/version.rb +1 -1
- data/lib/rtml/widget.rb +26 -14
- data/lib/rtml/widget_core/class_methods.rb +8 -4
- data/lib/rtml/widget_core/widget_accessor_instance_methods.rb +6 -6
- data/lib/rtml/widgets.rb +22 -3
- data/lib/rtml_routes.rb +1 -1
- data/rails_generators/rtml/rtml_generator.rb +3 -0
- data/rails_generators/rtml/templates/db/migrate/20100513165226_add_options_to_rtml_documents.rb +9 -0
- data/rails_generators/rtml/templates/db/migrate/20100513165242_remove_dom_elements_mirror.rb +16 -0
- data/rails_generators/rtml/templates/db/migrate/20100513165249_remove_dom_properties_mirror.rb +16 -0
- data/rails_generators/rtml/templates/lib/tasks/rtml.rake +1 -1
- data/rtml.gemspec +65 -0
- data/spec/controllers/rtml_controller_spec.rb +1 -1
- data/spec/integration/post_tests_spec.rb +8 -0
- data/spec/lib/rtml/high_level/variable_manager_spec.rb +8 -0
- data/spec/lib/rtml/routes_spec.rb +23 -22
- data/spec/lib/rtml/test/simulator/receipt_spec.rb +18 -0
- data/spec/lib/rtml/test/simulator_spec.rb +185 -0
- data/spec/lib/rtml/test/tml_application_spec.rb +119 -0
- data/spec/lib/rtml/test/variable_scope_spec.rb +65 -0
- data/spec/lib/rtml/widget_spec.rb +1 -0
- data/spec/lib/rtml/widgets_spec.rb +30 -0
- data/spec/models/rtml/document_spec.rb +8 -0
- data/spec/models/rtml/dom/screen_element_spec.rb +15 -0
- data/spec/models/rtml/instruction_spec.rb +2 -2
- data/spec/rtml_action_spec.rb +25 -0
- data/spec/spec_helper.rb +31 -1
- data/spec/support/app/controllers/post_tests_controller.rb +11 -0
- data/spec/support/app/views/inherited/instance_variables_test/display.rtml.erb +1 -0
- data/spec/support/config/boot.rb +1 -0
- data/spec/support/config/routes.rb +3 -2
- data/spec/support/db/rtml_test_db.sqlite3 +0 -0
- data/spec/support/raw_tml/avs.tml +27 -0
- data/spec/support/raw_tml/document_level_events.tml +18 -0
- data/spec/support/raw_tml/empty_screen.tml +15 -0
- data/spec/support/raw_tml/enter_amount.tml +40 -0
- data/spec/support/raw_tml/foreign_receiver.tml +10 -0
- data/spec/support/raw_tml/foreign_reference.tml +10 -0
- data/spec/support/raw_tml/hello_world.tml +13 -0
- data/spec/support/raw_tml/loop_x_times.tml +39 -0
- data/spec/support/raw_tml/one_screen_with_setvar.tml +8 -0
- data/spec/support/raw_tml/receipt.tml +15 -0
- data/spec/support/raw_tml/simulator.tml +122 -0
- data/spec/support/raw_tml/tmlvar_reference.tml +34 -0
- data/spec/support/raw_tml/user_input.tml +47 -0
- data/spec/support/raw_tml/valid_document.tml +6 -0
- data/spec/support/rspec/example_groups.rb +1 -1
- data/spec/support/rspec/matchers.rb +0 -11
- data/spec/widgets/document_variable_processing_spec.rb +25 -39
- data/spec/widgets/element_builder_spec.rb +4 -0
- data/spec/widgets/event_listener_spec.rb +9 -0
- data/spec/widgets/highlevel_variable_processing_spec.rb +27 -2
- data/spec/widgets/screen_variable_processing_spec.rb +34 -0
- data/spec/widgets/screens_spec.rb +22 -0
- data/spec/widgets/simulator_post_processors/card_parsers_spec.rb +70 -0
- data/spec/widgets/simulator_post_processors/submit_spec.rb +44 -0
- data/tasks/stats.rake +10 -0
- data/test/test_rtml_generator.rb +3 -0
- metadata +55 -49
- data/builtin/widgets/subroutine.rb +0 -54
- data/lib/rtml/high_level/subroutine.rb +0 -22
- data/lib/rtml/reverse_engineering/crawler.rb +0 -58
- data/lib/rtml/reverse_engineering/simulator.rb +0 -269
- data/lib/rtml/reverse_engineering/simulator/casting.rb +0 -9
- data/lib/rtml/reverse_engineering/simulator/snapshot.rb +0 -18
- data/lib/rtml/reverse_engineering/simulator/variable_lookup.rb +0 -32
- data/lib/rtml/reverse_engineering/simulator/variable_value.rb +0 -105
- data/spec/lib/rtml/reverse_engineering/crawler_spec.rb +0 -24
- data/spec/lib/rtml/reverse_engineering/simulator/variable_value_spec.rb +0 -120
- data/spec/lib/rtml/reverse_engineering/simulator_spec.rb +0 -96
- data/spec/support/config/tml_dom_ruleset.rb +0 -82
- data/spec/widgets/subroutine_spec.rb +0 -109
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
|
|
3
|
+
class Test::Unit::TestCase
|
|
4
|
+
def assert_tml_resembles(expected_hash, tml)
|
|
5
|
+
assert Rtml::Test::ResemblanceTest.new(expected_hash, target).pass?,
|
|
6
|
+
"Expected #{expected_hash.inspect} to resemble:\n\n#{tml}"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def assert_tml_not_resemble(expected_hash, tml)
|
|
10
|
+
assert !Rtml::Test::ResemblanceTest.new(expected_hash, target).pass?,
|
|
11
|
+
"Expected #{expected_hash.inspect} not to resemble:\n\n#{tml}"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
class Rtml::Test::VariableScope
|
|
2
|
+
class Variable
|
|
3
|
+
attr_reader :type, :perms, :format
|
|
4
|
+
attr_reader :value
|
|
5
|
+
attr_reader :name
|
|
6
|
+
|
|
7
|
+
def initialize(name, options = {})
|
|
8
|
+
options.stringify_keys!.reverse_merge(default_options)
|
|
9
|
+
@name = name.to_s
|
|
10
|
+
%w(type perms format).each do |key|
|
|
11
|
+
instance_variable_set("@#{key}", options[key].to_s) if options.key?(key)
|
|
12
|
+
instance_variable_set("@#{key}", default_options[key]) unless instance_variable_get("@#{key}")
|
|
13
|
+
end
|
|
14
|
+
self.value = options.delete('value') if options.key?('value')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# TODO: implement :format option
|
|
18
|
+
def perform_operation(op)
|
|
19
|
+
if op.keys?(:lo, :op) && op[:op] == 'number' # list length
|
|
20
|
+
raise Rtml::Errors::VariableError, "No :ro expected" if op.key?(:ro)
|
|
21
|
+
self.value = (op[:lo].to_s.split(/\;/).length)
|
|
22
|
+
elsif op.key?(:lo) && !op.keys?(:op, :ro) # assignment
|
|
23
|
+
self.value = op[:lo]
|
|
24
|
+
elsif op.keys?(:lo, :op, :ro) # operation
|
|
25
|
+
self.value = case op[:op]
|
|
26
|
+
when 'plus' then cast_value(op[:lo]) + cast_value(op[:ro])
|
|
27
|
+
when 'minus' then cast_value(op[:lo]) - cast_value(op[:ro])
|
|
28
|
+
when 'format' then raise Rtml::Errors::VariableError, "setvar[op=format] not yet implemented"
|
|
29
|
+
when 'item' then op[:lo].to_s.split(/\;/)[op[:ro].to_i]
|
|
30
|
+
else raise Rtml::Errors::VariableError, "Unknown operation: #{op[:op].inspect}"
|
|
31
|
+
end
|
|
32
|
+
else
|
|
33
|
+
raise Rtml::Errors::VariableError, "Expected :lo, :op, and :ro; or just :lo for assignment"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def value=(value)
|
|
38
|
+
@value = cast_value(value)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def cast_value(value)
|
|
42
|
+
case type
|
|
43
|
+
when 'integer' then value.to_i
|
|
44
|
+
when 'string' then value.to_s
|
|
45
|
+
when 'opaque' then value.to_s
|
|
46
|
+
when 'date' then value.kind_of?(DateTime) ? value : DateTime.parse(value.to_s)
|
|
47
|
+
else raise "Unknown type: #{type.inspect}"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
def default_options
|
|
53
|
+
{'type' => 'string', 'perms' => 'rwxrw', 'format' => nil, 'value' => ''}
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def initialize
|
|
58
|
+
@variables = {}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Returns a "snapshot" of this variable scope's current state. All known variables are returned, along with their
|
|
62
|
+
# types, values, etc.
|
|
63
|
+
def snapshot
|
|
64
|
+
@variables.values.collect do |variable|
|
|
65
|
+
{ :type => variable.type, :perms => variable.perms, :format => variable.format, :name => variable.name,
|
|
66
|
+
:value => variable.value }
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def inspect
|
|
71
|
+
@variables.collect do |name, variable|
|
|
72
|
+
"#{name}={value:#{variable.value.inspect} type:#{variable.type.inspect} perms:#{variable.perms.inspect} format:#{variable.format.inspect}}"
|
|
73
|
+
end.join("; ")
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Accepts a hash according to the TML rules (for example, keys should be :lo, :op, :ro)
|
|
77
|
+
def true_condition?(condition)
|
|
78
|
+
condition.reverse_merge!(:op => 'equal')
|
|
79
|
+
raise Rtml::Errors::VariableError, "Expected :lo, :op and :ro" unless condition.keys?(:lo, :op, :ro)
|
|
80
|
+
lo = literal_value(condition[:lo])
|
|
81
|
+
ro = literal_value(condition[:ro])
|
|
82
|
+
case condition[:op]
|
|
83
|
+
when 'equal' then lo == ro
|
|
84
|
+
when 'not_equal' then lo != ro
|
|
85
|
+
when 'less' then lo < ro
|
|
86
|
+
when 'less_or_equal' then lo <= ro
|
|
87
|
+
when 'contains' then lo =~ /#{Regexp::escape ro}/
|
|
88
|
+
else raise Rtml::Errors::VariableError, "Invalid operation: #{condition[:op].inspect}"
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def update(name, value)
|
|
93
|
+
find_variable(name).value = literal_value(value)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Accepts a hash, and updates each listed variable with the values in the hash.
|
|
97
|
+
def update_with(hash)
|
|
98
|
+
hash.each do |name, value|
|
|
99
|
+
update(name, value)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def literal_value(value_or_variable_name)
|
|
104
|
+
if value_or_variable_name.kind_of?(String) && value_or_variable_name =~ /^tmlvar\:/
|
|
105
|
+
value(value_or_variable_name[7..-1])
|
|
106
|
+
else
|
|
107
|
+
value_or_variable_name
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def perform_operation_on(variable_name, operation)
|
|
112
|
+
operation[:lo] = literal_value(operation[:lo]) if operation.key?(:lo)
|
|
113
|
+
operation[:ro] = literal_value(operation[:ro]) if operation.key?(:ro)
|
|
114
|
+
find_variable(variable_name).perform_operation(operation)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def exist?(name)
|
|
118
|
+
name = name.to_s unless name.kind_of?(String)
|
|
119
|
+
@variables[name]
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def find_variable(name)
|
|
123
|
+
name = name.to_s unless name.kind_of?(String)
|
|
124
|
+
@variables[name] || raise(Rtml::Errors::VariableError, "Undeclared variable #{name.inspect}")
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def declare_variable(name, options = {})
|
|
128
|
+
name = name.to_s unless name.kind_of?(String)
|
|
129
|
+
if @variables.key?(name)
|
|
130
|
+
raise Rtml::Errors::VariableError, "Already declared variable #{name.inspect} (it's a #{@variables[name].type})"
|
|
131
|
+
end
|
|
132
|
+
@variables[name] = Variable.new(name, options)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def variable_names
|
|
136
|
+
@variables.keys
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def value(name)
|
|
140
|
+
find_variable(name).value
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
alias_method :[], :value
|
|
144
|
+
alias_method :[]=, :update
|
|
145
|
+
alias_method :assign, :update
|
|
146
|
+
end
|
data/lib/rtml/version.rb
CHANGED
data/lib/rtml/widget.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'rtml/assigns'
|
|
2
|
+
|
|
1
3
|
# The Widget is the driving force behind RubyTML. It is interaction with Widgets of all shapes and sizes that produces
|
|
2
4
|
# a document model and, finally, the TML document itself. A Widget is so named because it is a generic class that can
|
|
3
5
|
# be made to encapsulate any desired functionality. The Rtml::Widget base class takes care of interfacing content
|
|
@@ -35,6 +37,8 @@
|
|
|
35
37
|
# ruby script/generate widget my_widget [entry_point1 entry_point2 . . .]
|
|
36
38
|
#
|
|
37
39
|
class Rtml::Widget
|
|
40
|
+
include Rtml::Assigns
|
|
41
|
+
|
|
38
42
|
# These are the accessors that RDoc uses to define what a particular RTML-specific attribute maps to.
|
|
39
43
|
#
|
|
40
44
|
# There are 3 kinds of accessors:
|
|
@@ -60,17 +64,22 @@ class Rtml::Widget
|
|
|
60
64
|
class_inheritable_array :targets
|
|
61
65
|
class_inheritable_array :shared_variables
|
|
62
66
|
class_inheritable_array :entry_points
|
|
67
|
+
class_inheritable_array :rtml_protected_instance_variables
|
|
63
68
|
read_inheritable_attribute(:targets) || write_inheritable_attribute(:targets, [])
|
|
64
69
|
read_inheritable_attribute(:shared_variables) || write_inheritable_attribute(:shared_variables, [])
|
|
65
70
|
read_inheritable_attribute(:entry_points) || write_inheritable_attribute(:entry_points, [])
|
|
71
|
+
read_inheritable_attribute(:rtml_protected_instance_variables) || write_inheritable_attribute(:rtml_protected_instance_variables, %w(
|
|
72
|
+
@document @parent @source_type
|
|
73
|
+
))
|
|
66
74
|
attr_reader :parent
|
|
67
75
|
attr_reader :source_type
|
|
68
76
|
extend Rtml::WidgetCore::ClassMethods
|
|
69
77
|
|
|
70
78
|
def validate_parent(*options)
|
|
71
79
|
options = options.flatten.collect { |o| o.kind_of?(String) ? o : o.to_s }
|
|
72
|
-
unless options.include?(parent.name)
|
|
73
|
-
|
|
80
|
+
unless options.include?(parent.name) || options.include?(parent.class.name) ||
|
|
81
|
+
((options.include?(:document) || options.include?('document')) && parent.kind_of?(Rtml::Document))
|
|
82
|
+
raise ArgumentError, "Expected parent to be one of #{options.to_sentence}; found #{parent.name}"
|
|
74
83
|
end
|
|
75
84
|
end
|
|
76
85
|
|
|
@@ -83,21 +92,24 @@ class Rtml::Widget
|
|
|
83
92
|
@widget_id ||= (@@widget_id_tracker += 1)
|
|
84
93
|
end
|
|
85
94
|
|
|
95
|
+
# Any method other than one of this widget's entry points will be delegated into #parent.
|
|
96
|
+
# The parent's methods are not known until runtime, and it's extraordinarily slow to generate
|
|
97
|
+
# delegation for those methods on the fly. Method_missing is the happy middle ground.
|
|
98
|
+
def method_missing(name, *args, &block)
|
|
99
|
+
name = name.to_s unless name.kind_of?(String)
|
|
100
|
+
return parent.send(name, *args, &block) unless entry_points.include?(name) || !parent.respond_to?(name)
|
|
101
|
+
# FIXME: Why does super raise an ArgumentError("no id given")?
|
|
102
|
+
raise NoMethodError, "Method missing: #{name}"
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def respond_to?(*a, &b)
|
|
106
|
+
super || parent.respond_to?(*a, &b)
|
|
107
|
+
end
|
|
108
|
+
|
|
86
109
|
def initialize(parent)
|
|
87
110
|
@parent = parent
|
|
88
111
|
set_source_type!
|
|
89
112
|
parent.widget_instances << self
|
|
90
|
-
# proxy parent methods into parent, unless they exist for widget already
|
|
91
|
-
singleton_class = (class << self; self; end)
|
|
92
|
-
(@parent.public_methods - self.public_methods).each do |proxy_method|
|
|
93
|
-
# don't delegate entry points -- this addresses the infinite loop issue in which calling a method that's been
|
|
94
|
-
# defined as an entry point but hasn't been created in the Widget itself would recurse back into the parent
|
|
95
|
-
# object forever.
|
|
96
|
-
unless entry_points.include? proxy_method
|
|
97
|
-
singleton_class.send(:delegate, proxy_method, :to => :parent)
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
|
|
101
113
|
|
|
102
114
|
self.class.shared_variables.each do |sv|
|
|
103
115
|
unless @parent.instance_variable_get("@#{sv[:name]}")
|
|
@@ -144,7 +156,7 @@ class Rtml::Widget
|
|
|
144
156
|
when Rtml::Document
|
|
145
157
|
@source_type = :document
|
|
146
158
|
else
|
|
147
|
-
@source_type = parent.name.to_sym
|
|
159
|
+
@source_type = parent.respond_to?(:name) ? parent.name.to_sym : parent.class.name.to_sym
|
|
148
160
|
end
|
|
149
161
|
end
|
|
150
162
|
end
|
|
@@ -106,10 +106,13 @@ module Rtml::WidgetCore::ClassMethods
|
|
|
106
106
|
|
|
107
107
|
# Goes through each of the targets of this Widget, looks up its mapping in Rtml::Widgets.mapping, and calls
|
|
108
108
|
# proxy_module.append_features(mapping) for each of those mappings.
|
|
109
|
+
#
|
|
109
110
|
def reinclude_proxy_module
|
|
110
111
|
targets.each do |target|
|
|
111
112
|
Rtml::Widgets.mapping(target).imbue(proxy_module)
|
|
112
113
|
end
|
|
114
|
+
# FIXME: Um... Maybe this is fine, but it seems out of place.
|
|
115
|
+
Rtml::Widgets.bases.each { |base| Rtml::Widgets.add_proxies_to_base(base) }
|
|
113
116
|
end
|
|
114
117
|
|
|
115
118
|
# Specifies entry points, which are names of methods that can be called from the targets to invoke this Widget.
|
|
@@ -119,10 +122,9 @@ module Rtml::WidgetCore::ClassMethods
|
|
|
119
122
|
#
|
|
120
123
|
def entry_point(*names)
|
|
121
124
|
names.each do |name|
|
|
122
|
-
name = name.
|
|
125
|
+
#name = name.to_sym unless name.kind_of?(Symbol)
|
|
123
126
|
unless entry_points.include?(name)
|
|
124
|
-
entry_points << name
|
|
125
|
-
add_entry_point(name)
|
|
127
|
+
entry_points << add_entry_point(name)
|
|
126
128
|
end
|
|
127
129
|
end
|
|
128
130
|
end
|
|
@@ -135,6 +137,7 @@ module Rtml::WidgetCore::ClassMethods
|
|
|
135
137
|
# raise Rtml::Errors::RulesViolationError,
|
|
136
138
|
# "Widget entry point #{entry_point} cannot be defined because it already exists!"
|
|
137
139
|
# end
|
|
140
|
+
#entry_point = entry_point.to_sym unless entry_point.is_a?(Symbol)
|
|
138
141
|
entry_point = entry_point.to_s if entry_point.is_a?(Symbol)
|
|
139
142
|
|
|
140
143
|
enter_from_hash = "#{entry_point}_from_hash"
|
|
@@ -174,6 +177,7 @@ module Rtml::WidgetCore::ClassMethods
|
|
|
174
177
|
end_code
|
|
175
178
|
proxy_module.class_eval code, __FILE__, line
|
|
176
179
|
reinclude_proxy_module
|
|
180
|
+
entry_point
|
|
177
181
|
end
|
|
178
182
|
|
|
179
183
|
# Returns true if the specified class is a valid target of this Widget
|
|
@@ -181,7 +185,7 @@ module Rtml::WidgetCore::ClassMethods
|
|
|
181
185
|
if base.respond_to?(:name)
|
|
182
186
|
name = base.name.underscore.sub(/^.*\//, '')
|
|
183
187
|
targets.each do |target|
|
|
184
|
-
if base.kind_of?(ActiveRecord::Base) # it's an instance, so we should check the tag name, not the class name
|
|
188
|
+
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
|
|
185
189
|
return true if target == base.name
|
|
186
190
|
else
|
|
187
191
|
return true if target == name
|
|
@@ -5,13 +5,13 @@ module Rtml::WidgetCore::WidgetAccessorInstanceMethods
|
|
|
5
5
|
|
|
6
6
|
delegate :class_widget_proxies, :class_widget_entry_points, :to => 'self.class'
|
|
7
7
|
|
|
8
|
-
def singleton_widgets; (class << self; self; end).class_widgets end
|
|
9
|
-
def singleton_widget_proxies; (class << self; self; end).class_widget_proxies end
|
|
10
|
-
def singleton_widget_entry_points; (class << self; self; end).class_widget_entry_points end
|
|
8
|
+
def singleton_widgets; (class << self; self; end).class_widgets ||= [] end
|
|
9
|
+
def singleton_widget_proxies; (class << self; self; end).class_widget_proxies ||= [] end
|
|
10
|
+
def singleton_widget_entry_points; (class << self; self; end).class_widget_entry_points ||= [] end
|
|
11
11
|
|
|
12
|
-
def widgets; singleton_widgets + class_widgets end
|
|
13
|
-
def widget_proxies; singleton_widget_proxies + class_widget_proxies end
|
|
14
|
-
def widget_entry_points; singleton_widget_entry_points + class_widget_entry_points end
|
|
12
|
+
def widgets; singleton_widgets + (self.class_widgets ||= []) end
|
|
13
|
+
def widget_proxies; singleton_widget_proxies + (self.class_widget_proxies ||= []) end
|
|
14
|
+
def widget_entry_points; singleton_widget_entry_points + (self.class_widget_entry_points ||= []) end
|
|
15
15
|
|
|
16
16
|
alias class_widget_methods class_widget_entry_points
|
|
17
17
|
alias singleton_widget_methods singleton_widget_entry_points
|
data/lib/rtml/widgets.rb
CHANGED
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
|
|
11
11
|
module Rtml::Widgets
|
|
12
12
|
class << self
|
|
13
|
+
# A list of all objects that have included Rtml::Widgets, marking them as compatible with Widgets.
|
|
14
|
+
attr_reader :bases
|
|
15
|
+
|
|
13
16
|
# The Widget mapping is a hash whose keys are symbols and whose values are instances of Module. The symbols
|
|
14
17
|
# represent either RTML models or TML tag names, while the Modules represent the proxy from the representation's
|
|
15
18
|
# class into the Widget itself. This way, the Module can be mixed-in with the target, and Widgets added after
|
|
@@ -25,12 +28,14 @@ module Rtml::Widgets
|
|
|
25
28
|
# target_instance.say_hi # => hello
|
|
26
29
|
# target_instance.say_bye # => goodbye
|
|
27
30
|
def mapping(key)
|
|
31
|
+
name = (key.respond_to?(:name) ? key.name : key.to_s).underscore
|
|
28
32
|
@widget_mapping ||= {}
|
|
29
|
-
@widget_mapping[
|
|
33
|
+
@widget_mapping[name] ||= Rtml::WidgetCore::WidgetProxy.new
|
|
30
34
|
end
|
|
31
35
|
|
|
32
36
|
# Returns all Widgets which affect the specified target.
|
|
33
37
|
def affecting(target)
|
|
38
|
+
target = (target.respond_to?(:name) ? target.name : target.to_s).underscore
|
|
34
39
|
mapping(target).proxied_widgets
|
|
35
40
|
end
|
|
36
41
|
|
|
@@ -44,14 +49,28 @@ module Rtml::Widgets
|
|
|
44
49
|
base.send(:extend, Rtml::WidgetCore::WidgetAccessorClassMethods)
|
|
45
50
|
load_widgets
|
|
46
51
|
add_proxies_to_base(base)
|
|
52
|
+
|
|
53
|
+
base.class_eval do
|
|
54
|
+
if defined?(initialize)
|
|
55
|
+
def initialize_with_widgets(*args, &block)
|
|
56
|
+
initialize_without_widgets(*args, &block)
|
|
57
|
+
Rtml::Widgets.add_proxies_to_base(self)
|
|
58
|
+
end
|
|
59
|
+
alias_method_chain :initialize, :widgets
|
|
60
|
+
else
|
|
61
|
+
def initialize
|
|
62
|
+
Rtml::Widgets.add_proxies_to_base(self)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
47
66
|
end
|
|
48
67
|
|
|
49
68
|
# Mixes the various proxy methods into the specified base.
|
|
50
69
|
def add_proxies_to_base(base)
|
|
51
|
-
target_name = base.respond_to?(:name) ? base.name.underscore.sub(/^.*\//, '') : nil
|
|
70
|
+
target_name = base.respond_to?(:name) ? (base.name || base.class.name).underscore.sub(/^.*\//, '') : nil
|
|
52
71
|
(@widget_mapping ||= {}).each do |key, mixin|
|
|
53
72
|
klass = base
|
|
54
|
-
if base.kind_of?
|
|
73
|
+
if base.kind_of?(ActiveRecord::Base) || base.kind_of?(Rtml::DocumentModelObject)
|
|
55
74
|
klass = class << base; self; end
|
|
56
75
|
end
|
|
57
76
|
|
data/lib/rtml_routes.rb
CHANGED
|
@@ -59,6 +59,9 @@ class RtmlGenerator < Rails::Generator::Base
|
|
|
59
59
|
20100127173146_add_parent_type_to_rtml_dom_elements.rb
|
|
60
60
|
20100208114234_create_rtml_states.rb
|
|
61
61
|
20100303021609_add_x_and_y_to_rtml_instructions.rb
|
|
62
|
+
20100513165226_add_options_to_rtml_documents.rb
|
|
63
|
+
20100513165242_remove_dom_elements_mirror.rb
|
|
64
|
+
20100513165249_remove_dom_properties_mirror.rb
|
|
62
65
|
)
|
|
63
66
|
|
|
64
67
|
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class RemoveDomElementsMirror < ActiveRecord::Migration
|
|
2
|
+
def self.up
|
|
3
|
+
drop_table :rtml_dom_elements
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def self.down
|
|
7
|
+
create_table :rtml_dom_elements do |t|
|
|
8
|
+
t.string :name
|
|
9
|
+
t.string :type, :default => 'Rtml::Dom::Element'
|
|
10
|
+
|
|
11
|
+
t.references :parent
|
|
12
|
+
t.references :document
|
|
13
|
+
t.timestamps
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
data/rails_generators/rtml/templates/db/migrate/20100513165249_remove_dom_properties_mirror.rb
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class RemoveDomPropertiesMirror < ActiveRecord::Migration
|
|
2
|
+
def self.up
|
|
3
|
+
drop_table :rtml_dom_properties
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def self.down
|
|
7
|
+
create_table :rtml_dom_properties do |t|
|
|
8
|
+
t.string :name
|
|
9
|
+
t.text :value
|
|
10
|
+
t.string :type
|
|
11
|
+
|
|
12
|
+
t.references :element
|
|
13
|
+
t.timestamps
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -5,9 +5,9 @@ end
|
|
|
5
5
|
|
|
6
6
|
# This is a tiny bit faster than the bootstrapper because we can skip some of the dependencies, which matters a lot more
|
|
7
7
|
# in potentially-often-run rake tasks.
|
|
8
|
-
module Rtml; module WidgetCore; end; end
|
|
9
8
|
require 'rtml'
|
|
10
9
|
unless defined?(Rtml::Widget)
|
|
10
|
+
module Rtml; module WidgetCore; end; end
|
|
11
11
|
require 'rtml/widget_core/class_methods'
|
|
12
12
|
require 'rtml/widget'
|
|
13
13
|
end
|