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.
Files changed (124) hide show
  1. data/History.txt +3 -0
  2. data/Manifest.txt +51 -13
  3. data/Rakefile +6 -1
  4. data/builtin/controllers/rtml_controller.rb +12 -1
  5. data/builtin/models/rtml/document.rb +24 -18
  6. data/builtin/models/rtml/document_model_object.rb +6 -0
  7. data/builtin/models/rtml/dom/collections/element_set.rb +6 -0
  8. data/builtin/models/rtml/dom/collections/property_set.rb +11 -0
  9. data/builtin/models/rtml/dom/element.rb +79 -27
  10. data/builtin/models/rtml/dom/frontend_element.rb +41 -20
  11. data/builtin/models/rtml/dom/property.rb +43 -26
  12. data/builtin/models/rtml/dom/screen_element.rb +13 -0
  13. data/builtin/widgets/document_variable_processing.rb +42 -18
  14. data/builtin/widgets/element_builder.rb +4 -4
  15. data/builtin/widgets/screen_variable_processing.rb +2 -2
  16. data/builtin/widgets/screen_variants.rb +31 -4
  17. data/builtin/widgets/screens.rb +13 -1
  18. data/builtin/widgets/static_content.rb +20 -6
  19. data/do_profile.rb +15 -0
  20. data/lib/extensions/action_controller/response.rb +0 -18
  21. data/lib/extensions/action_controller/routing/route_set.rb +28 -18
  22. data/lib/extensions/hpricot/doc.rb +3 -3
  23. data/lib/extensions/hpricot/elem.rb +3 -3
  24. data/lib/extensions/string.rb +2 -18
  25. data/lib/rtml.rb +0 -12
  26. data/lib/rtml/assigns.rb +32 -0
  27. data/lib/rtml/controller/document_generator.rb +9 -0
  28. data/lib/rtml/controller/render_helpers.rb +42 -18
  29. data/lib/rtml/controller/state.rb +2 -1
  30. data/lib/rtml/dependencies.rb +20 -15
  31. data/lib/rtml/dsl.rb +10 -10
  32. data/lib/rtml/environment.rb +13 -1
  33. data/lib/rtml/errors/application_error.rb +5 -0
  34. data/lib/rtml/errors/simulation_error.rb +4 -0
  35. data/lib/rtml/errors/variable_error.rb +5 -0
  36. data/lib/rtml/high_level/variable_manager.rb +11 -7
  37. data/lib/rtml/inherited_instance_variables.rb +8 -1
  38. data/lib/rtml/links.rb +17 -0
  39. data/lib/rtml/rules/dom_validation.rb +1 -0
  40. data/lib/rtml/test/builtin_variables.rb +33 -0
  41. data/lib/rtml/test/resemblance_test.rb +97 -0
  42. data/lib/rtml/test/screen.rb +126 -0
  43. data/lib/rtml/test/simulator.rb +240 -0
  44. data/lib/rtml/test/simulator_post_processors/base.rb +7 -0
  45. data/lib/rtml/test/simulator_post_processors/card_parsers.rb +32 -0
  46. data/lib/rtml/test/simulator_post_processors/receipt.rb +15 -0
  47. data/lib/rtml/test/simulator_post_processors/submit.rb +15 -0
  48. data/lib/rtml/test/spec.rb +14 -7
  49. data/lib/rtml/test/spec/matchers.rb +24 -0
  50. data/lib/rtml/test/tml_application.rb +331 -0
  51. data/lib/rtml/test/unit.rb +13 -0
  52. data/lib/rtml/test/variable_scope.rb +146 -0
  53. data/lib/rtml/version.rb +1 -1
  54. data/lib/rtml/widget.rb +26 -14
  55. data/lib/rtml/widget_core/class_methods.rb +8 -4
  56. data/lib/rtml/widget_core/widget_accessor_instance_methods.rb +6 -6
  57. data/lib/rtml/widgets.rb +22 -3
  58. data/lib/rtml_routes.rb +1 -1
  59. data/rails_generators/rtml/rtml_generator.rb +3 -0
  60. data/rails_generators/rtml/templates/db/migrate/20100513165226_add_options_to_rtml_documents.rb +9 -0
  61. data/rails_generators/rtml/templates/db/migrate/20100513165242_remove_dom_elements_mirror.rb +16 -0
  62. data/rails_generators/rtml/templates/db/migrate/20100513165249_remove_dom_properties_mirror.rb +16 -0
  63. data/rails_generators/rtml/templates/lib/tasks/rtml.rake +1 -1
  64. data/rtml.gemspec +65 -0
  65. data/spec/controllers/rtml_controller_spec.rb +1 -1
  66. data/spec/integration/post_tests_spec.rb +8 -0
  67. data/spec/lib/rtml/high_level/variable_manager_spec.rb +8 -0
  68. data/spec/lib/rtml/routes_spec.rb +23 -22
  69. data/spec/lib/rtml/test/simulator/receipt_spec.rb +18 -0
  70. data/spec/lib/rtml/test/simulator_spec.rb +185 -0
  71. data/spec/lib/rtml/test/tml_application_spec.rb +119 -0
  72. data/spec/lib/rtml/test/variable_scope_spec.rb +65 -0
  73. data/spec/lib/rtml/widget_spec.rb +1 -0
  74. data/spec/lib/rtml/widgets_spec.rb +30 -0
  75. data/spec/models/rtml/document_spec.rb +8 -0
  76. data/spec/models/rtml/dom/screen_element_spec.rb +15 -0
  77. data/spec/models/rtml/instruction_spec.rb +2 -2
  78. data/spec/rtml_action_spec.rb +25 -0
  79. data/spec/spec_helper.rb +31 -1
  80. data/spec/support/app/controllers/post_tests_controller.rb +11 -0
  81. data/spec/support/app/views/inherited/instance_variables_test/display.rtml.erb +1 -0
  82. data/spec/support/config/boot.rb +1 -0
  83. data/spec/support/config/routes.rb +3 -2
  84. data/spec/support/db/rtml_test_db.sqlite3 +0 -0
  85. data/spec/support/raw_tml/avs.tml +27 -0
  86. data/spec/support/raw_tml/document_level_events.tml +18 -0
  87. data/spec/support/raw_tml/empty_screen.tml +15 -0
  88. data/spec/support/raw_tml/enter_amount.tml +40 -0
  89. data/spec/support/raw_tml/foreign_receiver.tml +10 -0
  90. data/spec/support/raw_tml/foreign_reference.tml +10 -0
  91. data/spec/support/raw_tml/hello_world.tml +13 -0
  92. data/spec/support/raw_tml/loop_x_times.tml +39 -0
  93. data/spec/support/raw_tml/one_screen_with_setvar.tml +8 -0
  94. data/spec/support/raw_tml/receipt.tml +15 -0
  95. data/spec/support/raw_tml/simulator.tml +122 -0
  96. data/spec/support/raw_tml/tmlvar_reference.tml +34 -0
  97. data/spec/support/raw_tml/user_input.tml +47 -0
  98. data/spec/support/raw_tml/valid_document.tml +6 -0
  99. data/spec/support/rspec/example_groups.rb +1 -1
  100. data/spec/support/rspec/matchers.rb +0 -11
  101. data/spec/widgets/document_variable_processing_spec.rb +25 -39
  102. data/spec/widgets/element_builder_spec.rb +4 -0
  103. data/spec/widgets/event_listener_spec.rb +9 -0
  104. data/spec/widgets/highlevel_variable_processing_spec.rb +27 -2
  105. data/spec/widgets/screen_variable_processing_spec.rb +34 -0
  106. data/spec/widgets/screens_spec.rb +22 -0
  107. data/spec/widgets/simulator_post_processors/card_parsers_spec.rb +70 -0
  108. data/spec/widgets/simulator_post_processors/submit_spec.rb +44 -0
  109. data/tasks/stats.rake +10 -0
  110. data/test/test_rtml_generator.rb +3 -0
  111. metadata +55 -49
  112. data/builtin/widgets/subroutine.rb +0 -54
  113. data/lib/rtml/high_level/subroutine.rb +0 -22
  114. data/lib/rtml/reverse_engineering/crawler.rb +0 -58
  115. data/lib/rtml/reverse_engineering/simulator.rb +0 -269
  116. data/lib/rtml/reverse_engineering/simulator/casting.rb +0 -9
  117. data/lib/rtml/reverse_engineering/simulator/snapshot.rb +0 -18
  118. data/lib/rtml/reverse_engineering/simulator/variable_lookup.rb +0 -32
  119. data/lib/rtml/reverse_engineering/simulator/variable_value.rb +0 -105
  120. data/spec/lib/rtml/reverse_engineering/crawler_spec.rb +0 -24
  121. data/spec/lib/rtml/reverse_engineering/simulator/variable_value_spec.rb +0 -120
  122. data/spec/lib/rtml/reverse_engineering/simulator_spec.rb +0 -96
  123. data/spec/support/config/tml_dom_ruleset.rb +0 -82
  124. data/spec/widgets/subroutine_spec.rb +0 -109
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rtml::Test::VariableScope do
4
+ it "should raise if a variable is not defined" do
5
+ proc { subject[:name] = "Colin" }.should raise_error(Rtml::Errors::VariableError)
6
+ end
7
+
8
+ it "should allow variables to be defined" do
9
+ subject.declare_variable(:name)
10
+ subject.variable_names.should include('name')
11
+ end
12
+
13
+ it "should perform TML arithmetic: plus" do
14
+ subject.declare_variable(:counter, :type => :integer, :value => 1)
15
+ subject.perform_operation_on(:counter, :lo => '1', :op => 'plus', :ro => '2')
16
+ subject[:counter].should == 3
17
+ end
18
+
19
+ it "should perform TML arithmetic: minus" do
20
+ subject.declare_variable(:counter, :type => :integer, :value => 1)
21
+ subject.perform_operation_on(:counter, :lo => '1', :op => 'minus', :ro => '2')
22
+ subject[:counter].should == -1
23
+ end
24
+
25
+ it "should perform TML arithmetic: format"
26
+
27
+ it "should perform TML arithmetic: item" do
28
+ subject.declare_variable(:which)
29
+ subject.perform_operation_on(:which, :lo => 'one;two;three', :op => 'item', :ro => '1')
30
+ subject[:which].should == 'two'
31
+ end
32
+
33
+ it "should perform TML arithmetic: number" do
34
+ subject.declare_variable(:which)
35
+ subject.perform_operation_on(:which, :lo => 'one;two;three', :op => 'number')
36
+ subject[:which].should == '3'
37
+ end
38
+
39
+ it "should perform TML assignment" do
40
+ subject.declare_variable(:counter, :type => :integer, :value => 1)
41
+ subject.find_variable(:counter).perform_operation(:lo => '3')
42
+ subject[:counter].should == 3
43
+ end
44
+
45
+ it "should assign a dynamic value" do
46
+ subject.declare_variable(:counter, :type => :integer, :value => 1)
47
+ subject.declare_variable(:start, :type => :integer, :value => 5)
48
+ subject[:counter] = "tmlvar:start"
49
+ subject[:counter].should == 5
50
+ end
51
+
52
+ it "should assign another variable" do
53
+ # isn't this really the same as assigning a static value? because subject[:start] returns 1...
54
+ subject.declare_variable(:counter, :type => :integer, :value => 1)
55
+ subject.declare_variable(:start, :type => :integer, :value => 5)
56
+ subject[:counter] = subject[:start]
57
+ subject[:counter].should == 5
58
+ end
59
+
60
+ it "should assign a static value" do
61
+ subject.declare_variable(:counter, :type => :integer)
62
+ subject[:counter] = 5
63
+ subject[:counter].should == 5
64
+ end
65
+ end
@@ -52,6 +52,7 @@ describe Rtml::Widget do
52
52
  it "should not hang if entry point does not exist" do
53
53
  # If the test succeeds, the method will be missing. However, if it fails, it'll just hang the app,
54
54
  # so dev needs to figure out why the hard way.
55
+ # Update: Now I'm getting stack level errors, instead of hanging systems, when it fails. Progress.
55
56
  lambda { @doc.missing_widget_entry_point }.should raise_error(NoMethodError)
56
57
  end
57
58
  end
@@ -4,4 +4,34 @@ describe Rtml::Widgets do
4
4
  it "should find Widgets affecting a target" do
5
5
  Rtml::Widgets.affecting("document").should_not be_empty
6
6
  end
7
+
8
+ context "included into a class" do
9
+ context "with no widgets" do
10
+ subject { k = Class.new; k.send(:include, Rtml::Widgets); k.new }
11
+ it "should be able to iterate through widgets, even if there aren't any" do
12
+ subject.widgets.each { }
13
+ end
14
+ end
15
+
16
+ context "with widgets" do
17
+ subject do
18
+ k = Class.new
19
+ def k.name; "MyTest"; end
20
+ k.send(:include, Rtml::Widgets)
21
+
22
+ class MyWidget < Rtml::Widget
23
+ affects "MyTest"
24
+ entry_point :test_method
25
+ def test_method; 1; end
26
+ end
27
+
28
+ ### Rtml::Widgets.add_proxies_to_base(k)
29
+ k.new
30
+ end
31
+
32
+ it "should respond to entry points" do
33
+ subject.test_method.should == 1
34
+ end
35
+ end
36
+ end
7
37
  end
@@ -2,6 +2,14 @@ require File.join(__FILE__.gsub(/(.*)?\/spec\/.*$/, '\1'), 'spec/spec_helper')
2
2
 
3
3
  describe Rtml::Document do
4
4
  include Webrat::Matchers
5
+
6
+ it "should link multiple screens using strings properly" do
7
+ @doc = Rtml::Document.new
8
+ @doc.screen :first, "swipe_card_trans_reject"
9
+ @doc.screen "swipe_card_trans_reject"
10
+
11
+ @doc.to_tml.should =~ /next uri="#swipe_card_?[0-9]+/
12
+ end
5
13
 
6
14
  context "with one Screen instruction" do
7
15
  before :each do
@@ -8,4 +8,19 @@ describe Rtml::Dom::ScreenElement do
8
8
  it "should convert its name to a string after instantiation" do
9
9
  @ele.name.should be_a_kind_of(String)
10
10
  end
11
+
12
+ it "should not prepend ids with slashes in them with a #" do
13
+ @ele.property('next', "emb://embedded.tml")
14
+ @ele.to_tml.should_not =~ /\#/
15
+ end
16
+
17
+ it "should not lose # in submit econn" do
18
+ @ele.build :submit, :tgt => "a/path/to/somewhere", :econn => "#submit_err", :cache => "deny"
19
+ @ele.to_tml.should =~ /econn="#submit_err"/
20
+ end
21
+
22
+ it "should not prepend # if there is a colon (:)" do
23
+ @ele.next_screen "tmlvar:something"
24
+ @ele.to_tml.should =~ /next uri="tmlvar:something"/
25
+ end
11
26
  end
@@ -9,7 +9,7 @@ describe Rtml::Instruction do
9
9
  ' display "test"',
10
10
  ])
11
11
 
12
- rtml_document.should resemble(:tml => [:screen, {:screen => :display}])
12
+ rtml_document.should resemble_tml(:tml => [:screen, {:screen => :display}])
13
13
  end
14
14
 
15
15
  it "should produce a document from instances" do
@@ -21,7 +21,7 @@ describe Rtml::Instruction do
21
21
  rtml_document.setup_default_document
22
22
 
23
23
  instructions.each { |instruction| instruction.follow(rtml_document) }
24
- rtml_document.should resemble(:tml => [:screen, {:screen => :display}])
24
+ rtml_document.should resemble_tml(:tml => [:screen, {:screen => :display}])
25
25
  end
26
26
  end
27
27
 
@@ -0,0 +1,25 @@
1
+ require File.join(__FILE__.gsub(/(.*)?\/spec\/.*$/, '\1'), 'spec/spec_helper')
2
+
3
+ describe "RTML actions", :type => :controller do
4
+ controller_name :inherited
5
+
6
+ it "should copy variables into widgets" do
7
+ Rtml.action :instance_variables_test, :inherited do
8
+ @instance_variable = 5
9
+ screen(:index) { @instance_variable.should == 5 }
10
+ end
11
+
12
+ get :instance_variables_test, :ignore_state => true
13
+ response.should_not contain_errors
14
+ end
15
+
16
+ it "should copy variables into widgets" do
17
+ Rtml.action :instance_variables_test, :inherited do
18
+ @instance_variable = 5
19
+ screen(:display) { display }
20
+ end
21
+
22
+ get :instance_variables_test, :ignore_state => true
23
+ response.should contain("value: 5")
24
+ end
25
+ end
@@ -24,7 +24,9 @@ unless $rtml_spec_helper_already_loaded
24
24
  end
25
25
 
26
26
  require 'rtml/test/spec'
27
- Spec::Example::ExampleGroupFactory.default(RtmlExampleGroup)
27
+ require 'ruby-prof'
28
+ Spec::Example::ExampleGroupFactory.default(Rtml::Test::Spec::RtmlExampleGroup)
29
+
28
30
  # Now... this is redundant for working project tests, but absolutely critical for in-Rails tests.
29
31
  # TODO: Don't load it if it's redundant... Need to know whether it's in-rails or not for that, though.
30
32
  ActionController::Base.view_paths << File.join(File.dirname(__FILE__), 'support/app/views')
@@ -35,8 +37,36 @@ unless $rtml_spec_helper_already_loaded
35
37
  Dir[File.expand_path(File.join(File.dirname(__FILE__),'support/rspec','**','*.rb'))].each {|f| require f }
36
38
 
37
39
  Spec::Runner.configure do |config|
40
+ config.include(Rtml::Test::Spec::Matchers)
41
+
38
42
  config.after(:each) do
39
43
  Rtml::Document.destroy_all
40
44
  end
45
+
46
+ if ENV['PROFILE']
47
+ config.after(:all) do
48
+ # code here
49
+ if $started
50
+ puts "stop profiler for #{described_class}"
51
+ $started = nil
52
+ FileUtils.mkdir_p "profiled_specs"
53
+ file = "profiled_specs/#{described_class.to_s.underscore}.html"
54
+ result = RubyProf.stop
55
+
56
+ # You can then output the trace in different ways.
57
+ # Simply print a overview to stdout
58
+ printer = RubyProf::GraphHtmlPrinter.new(result)
59
+ printer.print(file, :min_percent => (ENV['MIN_PERCENT'] || 0.1).to_f)
60
+ end
61
+ end
62
+
63
+ config.before(:all) do
64
+ unless $started
65
+ $started = 1
66
+ puts "start profiler for #{described_class}"
67
+ RubyProf.start
68
+ end
69
+ end
70
+ end
41
71
  end
42
72
  end
@@ -0,0 +1,11 @@
1
+ class PostTestsController < ApplicationController
2
+ class Created < StandardError; end
3
+
4
+ def new
5
+
6
+ end
7
+
8
+ def create
9
+ raise Created, "Created."
10
+ end
11
+ end
@@ -0,0 +1 @@
1
+ <h1>value: <%=@instance_variable%></h1>
@@ -0,0 +1 @@
1
+ require File.expand_path("../../rails.rb", __FILE__)
@@ -1,3 +1,4 @@
1
1
  ActionController::Routing::Routes.draw do |map|
2
- map.connect_rtml :controller => 'rtml', :action => 'index', :format => 'rtml'
3
- end
2
+ map.connect_rtml :controller => 'inherited'
3
+ map.resources :post_tests
4
+ end
@@ -0,0 +1,27 @@
1
+ <?xml version="1.0" encoding="ISO-8859-1"?>
2
+ <tml cache="allow" xmlns="http://www.ingenico.co.uk/tml">
3
+ <head />
4
+ <!--app_start--> <screen id="app_start">
5
+ <next uri="#avs_address" />
6
+ <display>
7
+ start here
8
+ </display>
9
+ </screen>
10
+ <!--avs_address--> <screen id="avs_address">
11
+ <display>
12
+ <form>
13
+ Street Address / PO Box Number:
14
+ <input type="number" name="avs.address">
15
+ </form>
16
+ </display>
17
+ </screen>
18
+ <!--app_start_avs_completion--><screen id="app_start_14">
19
+ <next uri="#done" />
20
+ </screen>
21
+ <!--done--> <screen id="done" />
22
+ <!--assert--> <screen id="assert">
23
+ <display>
24
+ <h1>Assertion Error!</h1>On screen: <getvar name='oebr.prev_screen' />
25
+ </display>
26
+ </screen>
27
+ </tml>
@@ -0,0 +1,18 @@
1
+ <?xml version="1.0" encoding="ISO-8859-1"?>
2
+ <tml xmlns="http://www.ingenico.co.uk/tml" cache="deny">
3
+ <head>
4
+ <defaults cancel="#on_cancel" menu="#on_menu" />
5
+ </head>
6
+
7
+ <screen id="init" next="#idle">
8
+ </screen>
9
+
10
+ <screen id="idle" next="#idle">
11
+ <display>
12
+ <a href="#enter_amt">Make a Payment</a>
13
+ </display>
14
+ </screen>
15
+
16
+ <screen id="on_cancel"><display>cancel</display></screen>
17
+ <screen id="on_menu"><display>menu</display></screen>
18
+ </tml>
@@ -0,0 +1,15 @@
1
+ <?xml version="1.0" encoding="ISO-8859-1"?>
2
+ <tml cache="allow" xmlns="http://www.ingenico.co.uk/tml">
3
+ <head />
4
+ <vardcl type="integer" name="card.avs.zip" />
5
+ <vardcl type="integer" name="card.avs.address" />
6
+ <!--app_start--> <screen id="app_start">
7
+ <next uri="#app_start_a2" />
8
+ </screen>
9
+ <!--app_start_avs_completion--><screen id="app_start_a2" />
10
+ <!--assert--> <screen id="assert">
11
+ <display>
12
+ <h1>Assertion Error!</h1>On screen: <getvar name='oebr.prev_screen' />
13
+ </display>
14
+ </screen>
15
+ </tml>
@@ -0,0 +1,40 @@
1
+ <?xml version="1.0" encoding="ISO-8859-1"?>
2
+ <tml xmlns="http://www.ingenico.co.uk/tml" cache="deny">
3
+ <head />
4
+
5
+ <screen id="init" next="#idle">
6
+ <setvar name="payment.amount" lo="100" />
7
+ </screen>
8
+
9
+ <screen id="idle" next="#idle">
10
+ <display>
11
+ <a href="#enter_amt">Make a Payment</a>
12
+ </display>
13
+ </screen>
14
+
15
+ <screen id="enter_amt" next="#show_amt">
16
+ <display>
17
+ <form>
18
+ Enter Amount: <input type="number" format="$0*.00" name="payment.amount" />
19
+ </form>
20
+ </display>
21
+ </screen>
22
+
23
+ <screen id="show_amt" next="#swipe">
24
+ <display>
25
+ Amount Due: <getvar name="payment.amount" format="$0*.00" />
26
+ </display>
27
+ </screen>
28
+
29
+ <screen id="swipe" next="#risk">
30
+ <tform>
31
+ <card parser='mag' parser_params="read_data" />
32
+ </tform>
33
+ </screen>
34
+
35
+ <screen id="risk" next="#init">
36
+ <tform>
37
+ <card parser="mag" parser_params="risk_mgmt" />
38
+ </tform>
39
+ </screen>
40
+ </tml>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="ISO-8859-1"?>
2
+ <tml xmlns="http://www.ingenico.co.uk/tml" cache="deny">
3
+ <head />
4
+
5
+ <screen id="main_menu">
6
+ <display>
7
+ Main Menu!
8
+ </display>
9
+ </screen>
10
+ </tml>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="ISO-8859-1"?>
2
+ <tml xmlns="http://www.ingenico.co.uk/tml" cache="deny">
3
+ <head />
4
+
5
+ <screen id="idle" next="#idle" menu="spec/support/raw_tml/foreign_receiver.tml">
6
+ <display>
7
+ Hello, World!
8
+ </display>
9
+ </screen>
10
+ </tml>
@@ -0,0 +1,13 @@
1
+ <?xml version="1.0" encoding="ISO-8859-1"?>
2
+ <tml xmlns="http://www.ingenico.co.uk/tml" cache="deny">
3
+ <head />
4
+
5
+ <screen id="init" next="#idle">
6
+ </screen>
7
+
8
+ <screen id="idle" next="#idle">
9
+ <display>
10
+ Hello, World!
11
+ </display>
12
+ </screen>
13
+ </tml>
@@ -0,0 +1,39 @@
1
+ <?xml version="1.0" encoding="ISO-8859-1"?>
2
+ <tml xmlns="http://www.ingenico.co.uk/tml" cache="deny">
3
+ <head />
4
+
5
+ <vardcl name="counter" type="integer" />
6
+ <vardcl name="target" type="integer" />
7
+
8
+ <screen id="init" next="#idle">
9
+ <setvar name="counter" lo="0" />
10
+ <setvar name="target" lo="5" />
11
+ </screen>
12
+
13
+ <screen id="idle" next="#count">
14
+ <display>
15
+ <form>
16
+ How Many Loops? <input type="number" name="target" />
17
+ </form>
18
+ </display>
19
+ </screen>
20
+
21
+ <screen id="count" next="#loop" timeout="1">
22
+ <setvar name="counter" lo="tmlvar:counter" op="plus" ro="1" />
23
+ <display>
24
+ Counter: <getvar name="counter" />
25
+ </display>
26
+ </screen>
27
+
28
+ <screen id="loop">
29
+ <next uri="#count">
30
+ <variant uri="#complete" lo="tmlvar:counter" op="equal" ro="tmlvar:target" />
31
+ </next>
32
+ </screen>
33
+
34
+ <screen id="complete" next="#init" timeout="3">
35
+ <display>
36
+ Done: looped <getvar name="counter" /> times.
37
+ </display>
38
+ </screen>
39
+ </tml>