apotomo 0.1.1

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 (74) hide show
  1. data/Gemfile +10 -0
  2. data/Gemfile.lock +47 -0
  3. data/README +141 -0
  4. data/README.rdoc +141 -0
  5. data/Rakefile +78 -0
  6. data/TODO +36 -0
  7. data/app/cells/apotomo/child_switch_widget/switch.html.erb +1 -0
  8. data/app/cells/apotomo/child_switch_widget/switch.rhtml +1 -0
  9. data/app/cells/apotomo/deep_link_widget.rb +27 -0
  10. data/app/cells/apotomo/deep_link_widget/setup.html.erb +20 -0
  11. data/app/cells/apotomo/java_script_widget.rb +12 -0
  12. data/app/cells/apotomo/tab_panel_widget.rb +87 -0
  13. data/app/cells/apotomo/tab_panel_widget/display.html.erb +57 -0
  14. data/app/cells/apotomo/tab_widget.rb +18 -0
  15. data/app/cells/apotomo/tab_widget/display.html.erb +1 -0
  16. data/config/routes.rb +3 -0
  17. data/generators/widget/USAGE +15 -0
  18. data/generators/widget/templates/functional_test.rb +8 -0
  19. data/generators/widget/templates/view.html.erb +2 -0
  20. data/generators/widget/templates/view.html.haml +3 -0
  21. data/generators/widget/templates/widget.rb +8 -0
  22. data/generators/widget/widget_generator.rb +34 -0
  23. data/lib/apotomo.rb +59 -0
  24. data/lib/apotomo/caching.rb +37 -0
  25. data/lib/apotomo/container_widget.rb +10 -0
  26. data/lib/apotomo/deep_link_methods.rb +90 -0
  27. data/lib/apotomo/event.rb +9 -0
  28. data/lib/apotomo/event_handler.rb +23 -0
  29. data/lib/apotomo/event_methods.rb +102 -0
  30. data/lib/apotomo/invoke_event_handler.rb +24 -0
  31. data/lib/apotomo/javascript_generator.rb +57 -0
  32. data/lib/apotomo/persistence.rb +139 -0
  33. data/lib/apotomo/proc_event_handler.rb +18 -0
  34. data/lib/apotomo/rails/controller_methods.rb +161 -0
  35. data/lib/apotomo/rails/view_helper.rb +95 -0
  36. data/lib/apotomo/rails/view_methods.rb +7 -0
  37. data/lib/apotomo/request_processor.rb +92 -0
  38. data/lib/apotomo/stateful_widget.rb +8 -0
  39. data/lib/apotomo/transition.rb +46 -0
  40. data/lib/apotomo/tree_node.rb +186 -0
  41. data/lib/apotomo/version.rb +5 -0
  42. data/lib/apotomo/widget.rb +289 -0
  43. data/lib/apotomo/widget_shortcuts.rb +36 -0
  44. data/rails/init.rb +0 -0
  45. data/test/fixtures/application_widget_tree.rb +2 -0
  46. data/test/rails/controller_methods_test.rb +206 -0
  47. data/test/rails/rails_integration_test.rb +99 -0
  48. data/test/rails/view_helper_test.rb +77 -0
  49. data/test/rails/view_methods_test.rb +40 -0
  50. data/test/rails/widget_generator_test.rb +47 -0
  51. data/test/support/assertions_helper.rb +13 -0
  52. data/test/support/test_case_methods.rb +68 -0
  53. data/test/test_helper.rb +77 -0
  54. data/test/unit/apotomo_test.rb +20 -0
  55. data/test/unit/container_test.rb +20 -0
  56. data/test/unit/event_handler_test.rb +67 -0
  57. data/test/unit/event_methods_test.rb +83 -0
  58. data/test/unit/event_test.rb +30 -0
  59. data/test/unit/invoke_test.rb +123 -0
  60. data/test/unit/javascript_generator_test.rb +90 -0
  61. data/test/unit/onfire_integration_test.rb +19 -0
  62. data/test/unit/persistence_test.rb +240 -0
  63. data/test/unit/render_test.rb +203 -0
  64. data/test/unit/request_processor_test.rb +178 -0
  65. data/test/unit/stateful_widget_test.rb +135 -0
  66. data/test/unit/test_addressing.rb +111 -0
  67. data/test/unit/test_caching.rb +54 -0
  68. data/test/unit/test_jump_to_state.rb +89 -0
  69. data/test/unit/test_tab_panel.rb +72 -0
  70. data/test/unit/test_widget_shortcuts.rb +45 -0
  71. data/test/unit/transition_test.rb +33 -0
  72. data/test/unit/widget_shortcuts_test.rb +68 -0
  73. data/test/unit/widget_test.rb +24 -0
  74. metadata +215 -0
@@ -0,0 +1,99 @@
1
+ require File.join(File.dirname(__FILE__), %w(.. test_helper))
2
+
3
+ class RailsIntegrationTest < ActionController::TestCase
4
+ def simulate_request!
5
+ @controller.instance_eval { @apotomo_request_processor = nil }
6
+ @controller.session = Marshal.load(Marshal.dump(@controller.session))
7
+ end
8
+
9
+ context "A Rails controller" do
10
+ setup do
11
+ @controller = ApotomoController.new
12
+ @controller.session = {}
13
+ @controller.params = {}
14
+
15
+ #@mum = mouse_mock('mum', 'snuggle') { def snuggle; render; end }
16
+ @mum = MouseCell.new('mum', :snuggle)
17
+ @mum.instance_eval{ def snuggle; render; end }
18
+
19
+ @controller.instance_variable_set(:@mum, @mum)
20
+ @controller.instance_eval do
21
+ def widget
22
+ use_widgets do |root|
23
+ root << @mum
24
+ end
25
+
26
+ render :text => render_widget('mum')
27
+ end
28
+ end
29
+ end
30
+
31
+ should "freeze the widget tree once after each request" do
32
+ assert_equal 0, @controller.session.size
33
+
34
+ get 'widget'
35
+ assert_equal 1, @controller.session[:apotomo_stateful_branches].size
36
+ end
37
+
38
+ should "invoke a #use_widgets block only once per session" do
39
+ #assert_equal 1, @controller.apotomo_root.size
40
+
41
+ get 'widget'
42
+ assert_response :success
43
+ assert_equal 1, @controller.session[:apotomo_stateful_branches].size
44
+
45
+ simulate_request!
46
+
47
+ get 'widget'
48
+ assert_equal 1, @controller.session[:apotomo_stateful_branches].size
49
+ assert_response :success
50
+
51
+ simulate_request!
52
+
53
+ get 'widget'
54
+ assert_response :success
55
+ assert_equal 2, @controller.apotomo_root.size, "mum added multiple times"
56
+ end
57
+
58
+ should "provide the rails view helpers in state views" do
59
+ @mum.instance_eval do
60
+ def snuggle; render :view => :make_me_squeak; end
61
+ end
62
+
63
+ get 'widget'
64
+ assert_select "a", "Squeak!"
65
+ end
66
+
67
+ should "contain a freshly flushed tree when ?flush_widgets=1 is set" do
68
+ get 'widget'
69
+ assert_response :success
70
+ assert @controller.apotomo_request_processor.widgets_flushed?
71
+
72
+ simulate_request!
73
+
74
+ get 'widget'
75
+ assert_response :success
76
+ assert_not @controller.apotomo_request_processor.widgets_flushed?
77
+
78
+ simulate_request!
79
+
80
+ get 'widget', :flush_widgets => 1
81
+ assert_response :success # will fail if no #use_widgets block invoked
82
+ assert @controller.apotomo_request_processor.widgets_flushed?
83
+ end
84
+
85
+ should "render updates to the parent window for an iframe request" do
86
+ get 'widget'
87
+ assert_response :success
88
+ @controller.apotomo_root['mum'].respond_to_event :squeak, :with => :snuggle
89
+
90
+ simulate_request!
91
+
92
+ get 'render_event_response', :source => 'mum', :type => :squeak, :apotomo_iframe => true
93
+
94
+ assert_response :success
95
+ assert_equal 'text/html', @response.content_type
96
+ assert_equal "<html><body><script type='text/javascript' charset='utf-8'>\nvar loc = document.location;\nwith(window.parent) { setTimeout(function() { window.eval('<div id=\\\"mum\\\"><snuggle><\\/snuggle><\\/div>'); window.loc && loc.replace('about:blank'); }, 1) }\n</script></body></html>", @response.body
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,77 @@
1
+ require File.join(File.dirname(__FILE__), *%w[.. test_helper])
2
+
3
+ require 'action_view/test_case'
4
+
5
+ class ViewHelperTest < ActionView::TestCase
6
+ tests Apotomo::Rails::ViewHelper
7
+
8
+ context "A widget state view" do
9
+ setup do
10
+ barn_controller!
11
+
12
+ @cell = mouse_mock('mum')
13
+ end
14
+
15
+ teardown do
16
+ Apotomo.js_framework = :prototype
17
+ end
18
+
19
+ should "respond to #link_to_event" do
20
+ assert_dom_equal "<a href=\"#\" onclick=\"new Ajax.Request('/barn/render_event_response?source=mum&amp;type=footsteps', {asynchronous:true, evalScripts:true}); return false;\">Walk!</a>",
21
+ link_to_event("Walk!", :footsteps)
22
+ end
23
+
24
+ should "respond to #form_to_event" do
25
+ assert_dom_equal "<form onsubmit=\"new Ajax.Request('/barn/render_event_response?source=mum&amp;type=footsteps', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\" method=\"post\" action=\"/barn/render_event_response?source=mum&amp;type=footsteps\">",
26
+ form_to_event(:footsteps)
27
+ end
28
+
29
+ should "respond to #multipart_form_to_event" do
30
+ assert_dom_equal "<iframe name=\"apotomo_iframe\" id=\"apotomo_iframe\" style=\"display: none;\"></iframe><form enctype=\"multipart/form-data\" method=\"post\" action=\"/barn/render_event_response?apotomo_iframe=true&amp;source=mum&amp;type=footsteps\" target=\"apotomo_iframe\">",
31
+ multipart_form_to_event(:footsteps)
32
+ end
33
+
34
+ should "render multipart form if :multipart => true" do
35
+ assert_dom_equal "<iframe name=\"apotomo_iframe\" id=\"apotomo_iframe\" style=\"display: none;\"></iframe><form enctype=\"multipart/form-data\" method=\"post\" action=\"/barn/render_event_response?apotomo_iframe=true&amp;source=mum&amp;type=footsteps\" target=\"apotomo_iframe\">",
36
+ form_to_event(:footsteps, :multipart => true)
37
+ end
38
+
39
+ should "respond to #trigger_event" do
40
+ assert_dom_equal "new Ajax.Request(\"/barn/render_event_response?source=mum&type=footsteps\")",
41
+ trigger_event(:footsteps)
42
+ end
43
+
44
+ should "render RightJS if set" do
45
+ Apotomo.js_framework = :right
46
+
47
+ assert_dom_equal "new Xhr(\"/barn/render_event_response?source=mum&type=footsteps\", {evalScripts:true}).send()", trigger_event(:footsteps)
48
+ end
49
+
50
+ should "respond to #url_for_event" do
51
+ assert_equal("/barn/render_event_response?source=mum&type=footsteps", url_for_event(:footsteps))
52
+ end
53
+
54
+ should "respond to #widget_div" do
55
+ assert_equal '<div class="widget" id="mum">squeak!</div>', widget_div { "squeak!" }
56
+ end
57
+
58
+ context "#widget_javascript" do
59
+
60
+ should "usually render a javascript block" do
61
+ assert_equal "<script type=\"text/javascript\">\n//<![CDATA[\nalert(\"Beer!\")\n//]]>\n</script>", widget_javascript { 'alert("Beer!")' }
62
+ end
63
+
64
+ should "be quiet if suppress_js is set" do
65
+ @suppress_js = true ### TODO: use a local, not an instance variable.
66
+ assert_equal nil, widget_javascript { 'alert("Beer!")' }
67
+ end
68
+
69
+ should_eventually "capture" do
70
+ puts "capturing"
71
+ v = ActionView::Base.new
72
+ c = v.capture do "capture me!" end
73
+ puts c.inspect
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,40 @@
1
+ require File.join(File.dirname(__FILE__), *%w[.. test_helper])
2
+
3
+ class ViewMethodsTest < ActionController::TestCase
4
+ context "A Rails controller view" do
5
+ setup do
6
+ @controller = ApotomoController.new
7
+ @controller.extend Apotomo::Rails::ControllerMethods
8
+ @controller.session = {}
9
+
10
+ @controller.instance_variable_set(:@mum, mouse_mock('mum', 'snuggle') {def snuggle; render; end})
11
+ @controller.instance_eval do
12
+ def widget
13
+ use_widgets do |root|
14
+ root << @mum
15
+ end
16
+ render :inline => "<%= render_widget 'mum' %>"
17
+ end
18
+ end
19
+ end
20
+
21
+ should "respond to render_widget" do
22
+ get :widget
23
+ assert_select "#mum>snuggle"
24
+ end
25
+
26
+ should "respond to url_for_event" do
27
+ @controller.instance_eval do
28
+ def widget
29
+ use_widgets do |root|
30
+ root << @mum
31
+ end
32
+ render :inline => "<%= url_for_event :footsteps, :source => 'mum' %>"
33
+ end
34
+ end
35
+
36
+ get :widget
37
+ assert_equal "/apotomo/render_event_response?source=mum&type=footsteps", @response.body
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,47 @@
1
+ require File.join(File.dirname(__FILE__), %w(.. test_helper))
2
+ require 'rails_generator'
3
+ require 'rails_generator/scripts/generate'
4
+
5
+ Rails::Generator::Base.append_sources Rails::Generator::PathSource.new(:apotomo, File.join(File.dirname(__FILE__)+'/../../generators'))
6
+
7
+ class WidgetGeneratorTest < Test::Unit::TestCase
8
+ context "Running script/generate widget" do
9
+ setup do
10
+ FileUtils.mkdir_p(fake_rails_root)
11
+ @original_files = file_list
12
+ end
13
+
14
+ teardown do
15
+ FileUtils.rm_r(fake_rails_root)
16
+ end
17
+
18
+ context "MouseWidget squeak snuggle" do
19
+ should "create the standard assets" do
20
+ Rails::Generator::Scripts::Generate.new.run(%w(widget MouseWidget squeak snuggle), :destination => fake_rails_root)
21
+ files = (file_list - @original_files)
22
+ assert files.include?(fake_rails_root+"/app/cells/mouse_widget.rb")
23
+ assert files.include?(fake_rails_root+"/app/cells/mouse_widget/squeak.html.erb")
24
+ assert files.include?(fake_rails_root+"/app/cells/mouse_widget/snuggle.html.erb")
25
+ assert files.include?(fake_rails_root+"/test/widgets/mouse_widget_test.rb")
26
+ end
27
+
28
+ should "create haml assets with --haml" do
29
+ Rails::Generator::Scripts::Generate.new.run(%w(widget MouseWidget squeak snuggle --haml), :destination => fake_rails_root)
30
+ files = (file_list - @original_files)
31
+ assert files.include?(fake_rails_root+"/app/cells/mouse_widget.rb")
32
+ assert files.include?(fake_rails_root+"/app/cells/mouse_widget/squeak.html.haml")
33
+ assert files.include?(fake_rails_root+"/app/cells/mouse_widget/snuggle.html.haml")
34
+ assert files.include?(fake_rails_root+"/test/widgets/mouse_widget_test.rb")
35
+ end
36
+ end
37
+ end
38
+
39
+ private
40
+ def fake_rails_root
41
+ File.join(File.dirname(__FILE__), 'rails_root')
42
+ end
43
+
44
+ def file_list
45
+ Dir.glob(File.join(fake_rails_root, "**/*"))
46
+ end
47
+ end
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+
3
+ module Apotomo
4
+ module AssertionsHelper
5
+ def assert_selekt(content, *args)
6
+ assert_select(HTML::Document.new(content).root, *args)
7
+ end
8
+
9
+ def assert_not(assertion)
10
+ assert !assertion
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,68 @@
1
+ module Apotomo
2
+ module TestCaseMethods
3
+ # Provides a ready-to-use mouse widget instance.
4
+ def mouse_mock(id='mouse', start_state=:eating, opts={}, &block)
5
+ #mouse = mouse_class_mock.new(id, start_state, opts)
6
+ mouse = MouseCell.new(id, start_state, opts)
7
+ mouse.instance_eval &block if block_given?
8
+ mouse.controller = @controller
9
+ mouse
10
+ end
11
+
12
+ def mouse_class_mock(&block)
13
+ klass = Class.new(MouseCell)
14
+ klass.instance_eval &block if block_given?
15
+ klass
16
+ end
17
+
18
+ def mum_and_kid!
19
+ @mum = mouse_mock('mum', :answer_squeak)
20
+ @mum << @kid = mouse_mock('kid', :peek)
21
+
22
+ @mum.respond_to_event :squeak, :with => :answer_squeak
23
+ @mum.respond_to_event :squeak, :from => 'kid', :with => :alert
24
+ @mum.respond_to_event :footsteps, :with => :escape
25
+
26
+ @kid.respond_to_event :footsteps, :with => :peek
27
+
28
+
29
+ @mum.instance_eval do
30
+ def list; @list ||= []; end
31
+
32
+ def answer_squeak; self.list << 'answer squeak'; render :text => "squeak", :render_children => false; end
33
+ def alert; self.list << 'be alerted'; render :text => "alert!", :render_children => false; end
34
+ def escape; self.list << 'escape'; render :text => "escape", :render_children => false; end
35
+ end
36
+
37
+ @kid.instance_eval do
38
+ def peek; root.list << 'peek'; render :text => "" end
39
+ end
40
+
41
+ @mum
42
+ end
43
+
44
+ def barn_controller!
45
+ @controller = Class.new(ActionController::Base) do
46
+ def self.default_url_options; {:controller => :barn}; end
47
+ end.new
48
+ @controller.class.instance_eval { include Apotomo::Rails::ControllerMethods }
49
+ @controller.extend ActionController::UrlWriter
50
+ @controller.params = {}
51
+ @controller.session = {}
52
+ end
53
+
54
+ def hibernate_widget(widget, session = {})
55
+ widget.freeze_to(session)
56
+
57
+ session = Marshal.load(Marshal.dump(session))
58
+
59
+ Apotomo::StatefulWidget.thaw_from(session)
60
+ end
61
+
62
+ def hibernate(widget, session = {})
63
+ Apotomo::StatefulWidget.freeze_for(session, widget)
64
+ session = Marshal.load(Marshal.dump(session))
65
+ Apotomo::StatefulWidget.thaw_for(session, widget('apotomo/widget', 'root'))
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,77 @@
1
+ # wycats says...
2
+ require 'bundler'
3
+ Bundler.setup
4
+
5
+ #require 'rubygems'
6
+ require 'shoulda'
7
+ require 'mocha'
8
+ require 'mocha/integration'
9
+
10
+
11
+ require 'cells'
12
+ Cell::Base.add_view_path File.expand_path(File.dirname(__FILE__) + "/fixtures")
13
+
14
+ puts Cell::Base.view_paths
15
+
16
+ require 'apotomo'
17
+ require 'apotomo/widget_shortcuts'
18
+ require 'apotomo/rails/controller_methods'
19
+ require 'apotomo/rails/view_methods'
20
+ #require 'apotomo/assertions_helper'
21
+
22
+
23
+
24
+
25
+ # Load test support files.
26
+ Dir[File.join(File.dirname(__FILE__), *%w[support ** *.rb]).to_s].each { |f| require f }
27
+
28
+
29
+ Test::Unit::TestCase.class_eval do
30
+ include Apotomo::WidgetShortcuts
31
+ include Apotomo::TestCaseMethods
32
+ include Apotomo::AssertionsHelper
33
+
34
+ def setup
35
+ @controller = ApotomoController.new
36
+ @request = ActionController::TestRequest.new
37
+ @response = ActionController::TestResponse.new
38
+ @controller.request = @request
39
+ @controller.response = @response
40
+ @controller.params = {}
41
+ @controller.session = @session = {}
42
+ end
43
+ end
44
+
45
+ class ApotomoController < ActionController::Base
46
+ include Apotomo::Rails::ControllerMethods
47
+ end
48
+
49
+ class MouseCell < Apotomo::StatefulWidget
50
+ def eating; render; end
51
+ end
52
+
53
+ class RenderingTestCell < Apotomo::StatefulWidget
54
+ attr_reader :brain
55
+ attr_reader :rendered_children
56
+
57
+
58
+
59
+ def jump
60
+ jump_to_state :check_state
61
+ end
62
+ end
63
+
64
+
65
+
66
+ # We need to setup a fake route for the controller tests.
67
+ ActionController::Routing::Routes.draw do |map|
68
+ map.connect 'apotomo/:action', :controller => 'apotomo'
69
+ map.connect 'barn/:action', :controller => 'barn'
70
+ end
71
+ require File.join(File.dirname(__FILE__), '..', 'config/routes.rb') ### TODO: let rails engine handle that.
72
+
73
+
74
+
75
+ module ::Rails
76
+ def logger(*args); end
77
+ end
@@ -0,0 +1,20 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class ApotomoTest < Test::Unit::TestCase
4
+ context "The main module" do
5
+ should "save the JavascriptGenerator instance when setting js_framework" do
6
+ Apotomo.js_framework = :jquery
7
+ assert_respond_to Apotomo.js_generator, :jquery
8
+ end
9
+
10
+ should "have an accessor for js_framework" do
11
+ Apotomo.js_framework = :jquery
12
+ assert_equal :jquery, Apotomo.js_framework
13
+ end
14
+
15
+ should "have a setup method" do
16
+ Apotomo.setup { |config| config.js_framework = :prototype }
17
+ assert_respond_to Apotomo.js_generator, :prototype
18
+ end
19
+ end
20
+ end