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,111 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
2
+
3
+
4
+ class AddressingTest < Test::Unit::TestCase
5
+ include Apotomo::UnitTestCase
6
+
7
+ def test_url_fragment
8
+ frag = Apotomo::DeepLinkMethods::UrlFragment.new("tabs=first/mouse=eating")
9
+
10
+ assert_equal "tabs=first/mouse=eating", frag.to_s
11
+ assert_equal "first", frag[:tabs]
12
+ assert_equal "first", frag['tabs']
13
+ assert_equal "eating", frag[:mouse]
14
+ assert_equal "eating", frag['mouse']
15
+ assert_equal nil, frag[:non_existent]
16
+
17
+ frag = Apotomo::DeepLinkMethods::UrlFragment.new(nil)
18
+ assert_equal nil, frag[:non_existent]
19
+ end
20
+
21
+ def test_url_fragment_accessor
22
+ assert_kind_of Apotomo::DeepLinkMethods::UrlFragment, mouse_mock.url_fragment
23
+ end
24
+
25
+ def test_url_fragment_blank?
26
+ assert Apotomo::DeepLinkMethods::UrlFragment.new("").blank?
27
+ end
28
+
29
+
30
+ def test_responds_to_url_change?
31
+ m = mouse_mock
32
+ assert ! m.responds_to_url_change?
33
+
34
+ m.respond_to_event :urlChange, :with => :eating
35
+ assert m.responds_to_url_change?, "should be true as an :urlChanged listener is attached."
36
+
37
+ # test with explicit source:
38
+ m = mouse_mock
39
+ m.respond_to_event :urlChange, :with => :eating, :from => 'mouse'
40
+ assert m.responds_to_url_change?, "should be true as an :urlChanged listener is attached."
41
+ end
42
+
43
+ def test_deep_link_addressing
44
+ t = mouse_mock('top', :upside) do
45
+ def local_fragment; "top=upside"; end
46
+ end
47
+ b = mouse_mock('bottom', :downside) do
48
+ def local_fragment; "bottom=downside"; end
49
+ end
50
+
51
+ t.respond_to_event :urlChange, :with => :eating
52
+ b.respond_to_event :urlChange, :with => :eating
53
+
54
+ t << b
55
+ b << j = cell(:mouse, :eating, 'jerry')
56
+
57
+
58
+ assert_equal "top=upside", t.local_fragment
59
+ assert_equal "v", t.url_fragment_for("v")
60
+
61
+ assert_equal "bottom=downside", b.local_fragment
62
+ assert_equal "top=upside/bottom=downside", b.url_fragment_for
63
+ assert_equal "top=upside/v", b.url_fragment_for('v')
64
+
65
+ assert_equal nil, j.local_fragment
66
+ assert_equal "top=upside/bottom=downside", j.url_fragment_for
67
+ assert_equal "top=upside/bottom=downside/jerry", j.url_fragment_for('jerry')
68
+ end
69
+
70
+
71
+ def test_default_local_fragment
72
+ assert_equal nil, mouse_mock.local_fragment
73
+ end
74
+
75
+
76
+ def test_responds_to_url_change_for
77
+ m = mouse_mock do
78
+ def eating; render :nothing => :true; end
79
+ end
80
+
81
+ assert ! m.responds_to_url_change_for?(""), "should return false by default"
82
+ end
83
+
84
+
85
+ def test_path
86
+ w= cell(:my_test, :some, 'root')
87
+ assert_equal w.path, 'root'
88
+
89
+ w << a= cell(:my_test, :some, 'a')
90
+
91
+ assert_equal a.path, 'root/a'
92
+ end
93
+
94
+
95
+ def test_find
96
+ root = widget("apotomo/stateful_widget", :widget_content, 'root')
97
+ root << a = widget("apotomo/stateful_widget", :widget_content, 'a')
98
+ a << aa = widget("apotomo/stateful_widget", :widget_content, 'a')
99
+
100
+ assert_equal a, root.find_by_id("a")
101
+ assert_equal a, root.find_by_path("a")
102
+ assert_equal a, root.find_by_path(:a)
103
+ assert_equal aa, root.find_by_path("a a")
104
+ end
105
+
106
+ end
107
+
108
+ class MyTestCell < Apotomo::StatefulWidget
109
+
110
+
111
+ end
@@ -0,0 +1,54 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
2
+
3
+
4
+ class ApotomoCachingTest < Test::Unit::TestCase
5
+ include Apotomo::UnitTestCase
6
+
7
+ def setup
8
+ super
9
+ @controller.session= {}
10
+ @cc = CachingCell.new('caching_cell', :start)
11
+ @cc.controller = @controller
12
+ end
13
+
14
+
15
+ def test_caching_with_instance_version_proc
16
+ unless ActionController::Base.cache_configured?
17
+ throw Exception.new "cache_configured? returned false. You may enable caching in your config/environments/test.rb to make this test pass."
18
+ return
19
+ end
20
+ c1 = @cc.invoke
21
+ c2 = @cc.invoke
22
+ assert_equal c1, c2
23
+
24
+ @cc.dirty!
25
+
26
+ c3 = @cc.invoke
27
+ assert c2 != c3
28
+ end
29
+
30
+ end
31
+
32
+
33
+ class CachingCell < Apotomo::StatefulWidget
34
+
35
+ cache :cached_state
36
+
37
+ transition :in => :cached_state
38
+
39
+
40
+ def start
41
+ jump_to_state :cached_state
42
+ end
43
+
44
+ def cached_state
45
+ @counter ||= 0
46
+ @counter += 1
47
+ "#{@counter}"
48
+
49
+ end
50
+
51
+ def not_cached_state
52
+ "i'm really static"
53
+ end
54
+ end
@@ -0,0 +1,89 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
2
+
3
+ ### DISCUSS: move some tests from PersistenceTest to this test file.
4
+
5
+
6
+ class InterStateTest < ActionController::TestCase
7
+ include Apotomo::UnitTestCase
8
+
9
+ # do we really jump to the correct state?
10
+ # and: are all state ivars remembered while jumping?
11
+ def test_three_state_jumps
12
+ w = StateJumpCell.new('x', :one)
13
+ w.controller = @controller
14
+
15
+ c = w.invoke # :one -> :two -> :three
16
+
17
+ assert_state w, :three
18
+ puts "brain dump:"
19
+ puts w.brain.inspect
20
+
21
+ assert w.brain.include?("@var")
22
+ assert w.brain.include?("@one");
23
+ assert_equal "three,one", c
24
+ end
25
+
26
+
27
+ def test_brain_reset_when_invoking_a_start_state
28
+ w = StateJumpCell.new('x', :counter)
29
+ w.controller = @controller
30
+
31
+ assert_equal "1", w.invoke
32
+ # another #invoke will flush brain:
33
+ assert_equal "1", w.invoke
34
+ end
35
+
36
+ def test_brain_reset_when_jumping_to_a_start_state
37
+ w = StateJumpCell.new('x', :counter)
38
+ w.controller = @controller
39
+ w.instance_eval do
40
+ def back_to_start
41
+ jump_to_state :counter # :counter is a start state.
42
+ end
43
+ end
44
+
45
+ assert_equal "1", w.invoke
46
+ # if using #jump_to_state there should be NO brain flush:
47
+ assert_equal "2", w.invoke_state(:back_to_start)
48
+ end
49
+
50
+
51
+ def test_last_state
52
+ w = StateJumpCell.new('x', :four)
53
+ w.controller = @controller
54
+ c = w.invoke
55
+ assert_equal w.last_state, :four
56
+ end
57
+
58
+ end
59
+
60
+
61
+ class StateJumpCell < Apotomo::StatefulWidget
62
+ attr_reader :brain
63
+ def one
64
+ @var = "one"
65
+ @one = "one"
66
+ jump_to_state :two
67
+ end
68
+
69
+ def two
70
+ @var = "two"
71
+ jump_to_state :three
72
+ end
73
+
74
+ def three
75
+ @var = "three"
76
+ render :text => "#{@var},#{@one}"
77
+ end
78
+
79
+ def four
80
+ render :text => ""
81
+ end
82
+
83
+ def counter
84
+ @counter ||= 0
85
+ @counter += 1
86
+ render :text => @counter.to_s
87
+ end
88
+
89
+ end
@@ -0,0 +1,72 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
2
+
3
+
4
+ class TabPanelTest < Test::Unit::TestCase
5
+ include Apotomo::UnitTestCase
6
+
7
+ def test_responds_to_url_change_for?
8
+ fragment = Apotomo::DeepLinkMethods::UrlFragment
9
+
10
+ w = tab_panel('mice', :is_url_listener => true)
11
+ w.current_child_id = 'jerry'
12
+
13
+ assert ! w.responds_to_url_change_for?(fragment.new ""), "shouldn't respond to emtpy url"
14
+ assert ! w.responds_to_url_change_for?(fragment.new "cats=tom"), "shouldn't respond to foreign url"
15
+ assert ! w.responds_to_url_change_for?(fragment.new "mice=jerry")
16
+ assert ! w.responds_to_url_change_for?(fragment.new "mice="), "shouldn't respond to invalid url"
17
+ assert w.responds_to_url_change_for?(fragment.new "mice=berry")
18
+ end
19
+
20
+ def test_local_fragment
21
+ w = tab_panel('mice')
22
+ w.current_child_id = 'jerry'
23
+
24
+ assert_equal "mice=jerry", w.local_fragment
25
+ end
26
+
27
+ def test_find_current_child_from_query
28
+ w = tab_panel('mice')
29
+ w << tab('jerry')
30
+ w << tab('berry')
31
+ w << tab('micky')
32
+
33
+ w.controller = controller
34
+
35
+
36
+ # default child:
37
+ assert_equal 'jerry', w.find_current_child.name
38
+ ### FIXME: i hate the usage of global parameters:
39
+ controller.params = {'mice' => 'micky', :deep_link => 'mice=berry'}
40
+
41
+ assert_equal 'micky', w.find_current_child.name, "didn't process the query string ?mice=micky"
42
+ end
43
+
44
+ def test_find_current_child_from_fragment
45
+ w = tab_panel('mice', :is_url_listener => true)
46
+ w << tab('jerry')
47
+ w << tab('berry')
48
+ w << tab('micky')
49
+
50
+ w.controller = controller
51
+
52
+ ### FIXME: i hate the usage of global parameters:
53
+ controller.params = {'mice' => 'micky', :deep_link => 'mice=berry'}
54
+
55
+ assert_equal 'berry', w.find_current_child.name, "didn't process the url fragment 'mice=berry'"
56
+ end
57
+
58
+ def test_url_fragment_for_tab
59
+ w = tab_panel('mice', :is_url_listener => true)
60
+ w << j= tab('jerry')
61
+ j << c= tab_panel('jerrys_kids', :is_url_listener => true)
62
+ c << r= tab('jerry_jr')
63
+ w << b= tab('berry')
64
+
65
+ w.current_child_id = 'jerry'
66
+
67
+ assert_equal "mice=berry", w.url_fragment_for_tab(b)
68
+ assert_equal "mice=jerry", w.url_fragment_for_tab(j)
69
+
70
+ assert_equal "mice=jerry/jerrys_kids=jerry_jr", c.url_fragment_for_tab(r)
71
+ end
72
+ end
@@ -0,0 +1,45 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
2
+
3
+
4
+ # fixture:
5
+ module My
6
+ class TestCell < Apotomo::StatefulWidget
7
+ def a_state
8
+ "a_state"
9
+ end
10
+ end
11
+
12
+ class TestWidget < Apotomo::StatefulWidget
13
+ def a_state
14
+ "a_state"
15
+ end
16
+ end
17
+ end
18
+
19
+ class MyTestWidgetTree < Apotomo::WidgetTree
20
+ def draw(root)
21
+ root << widget('apotomo/stateful_widget', :widget_content, 'widget_one')
22
+ root << cell(:my_test, :a_state, 'my_test_cell')
23
+ root << switch('my_switch') << widget('apotomo/stateful_widget', :widget_content, :child_widget)
24
+ root << section('my_section')
25
+ root << widget('apotomo/stateful_widget', :widget_content, :widget_three)
26
+ #root ### FIXME! find a way to return nothing by default.
27
+ end
28
+ end
29
+
30
+
31
+ class WidgetShortcutsTest < Test::Unit::TestCase
32
+ include Apotomo::UnitTestCase
33
+
34
+
35
+ def test_cell
36
+ assert_kind_of My::TestCell, cell("my/test", :a_state, 'my_test_cell')
37
+ end
38
+
39
+ def test_widget
40
+ w = widget("my/test_widget", :a_state, 'my_test_cell')
41
+ assert_kind_of My::TestWidget, w
42
+ assert_equal "my_test_cell", w.name
43
+ end
44
+
45
+ end
@@ -0,0 +1,33 @@
1
+ require File.join(File.dirname(__FILE__), *%w[.. test_helper])
2
+
3
+ class TransitionTest < Test::Unit::TestCase
4
+ context "Calling #next_state_for" do
5
+ setup do
6
+ @mum = Object.new
7
+ @mum.class.instance_eval do
8
+ include Apotomo::Transition
9
+ end
10
+ end
11
+
12
+ should "return nil when no transition is defined" do
13
+ assert_not @mum.send(:next_state_for, :snuggle)
14
+ end
15
+
16
+ should "return the defined next state" do
17
+ @mum.class.instance_eval do
18
+ transition :from => :snuggle, :to => :sleep
19
+ end
20
+
21
+ assert_equal :sleep, @mum.send(:next_state_for, :snuggle)
22
+ end
23
+
24
+ should "return the state that was defined last" do
25
+ @mum.class.instance_eval do
26
+ transition :from => :snuggle, :to => :sleep
27
+ transition :from => :snuggle, :to => :snore
28
+ end
29
+
30
+ assert_equal :snore, @mum.send(:next_state_for, :snuggle)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,68 @@
1
+ require File.join(File.dirname(__FILE__), *%w[.. test_helper])
2
+
3
+ class MumWidget < MouseCell; end
4
+
5
+ class WidgetShortcutsTest < Test::Unit::TestCase
6
+ context "#cell" do
7
+ should "create a MouseCell instance for backward-compatibility" do
8
+ assert_kind_of MouseCell, cell(:mouse, :eating, 'mum')
9
+ end
10
+ end
11
+
12
+ context "#widget" do
13
+ context "with all arguments" do
14
+ setup do
15
+ @mum = widget(:mum_widget, 'mum', :eating)
16
+ end
17
+
18
+ should "create a MumWidget instance" do
19
+ assert_kind_of MumWidget, @mum
20
+ assert_equal :eating, @mum.instance_variable_get(:@start_state)
21
+ assert_equal 'mum', @mum.name
22
+ end
23
+ end
24
+
25
+ context "with id only" do
26
+ setup do
27
+ @mum = widget(:mum_widget, 'mum')
28
+ end
29
+
30
+ should "create a MumWidget instance with :display start state" do
31
+ assert_kind_of MumWidget, @mum
32
+ assert_equal :display, @mum.instance_variable_get(:@start_state)
33
+ assert_equal 'mum', @mum.name
34
+ end
35
+ end
36
+
37
+ should "yield itself" do
38
+ @mum = widget(:mum_widget, :snuggle, 'mum') do |mum|
39
+ assert_kind_of MumWidget, mum
40
+ mum << widget(:mum_widget, 'kid', :sleep)
41
+ end
42
+ assert_equal 2, @mum.size
43
+ assert_kind_of MumWidget, @mum['kid']
44
+ end
45
+ end
46
+
47
+ context "#container" do
48
+ setup do
49
+ @family = container('family')
50
+ end
51
+
52
+ should "create a ContainerWidget instance" do
53
+ assert_kind_of ::Apotomo::ContainerWidget, @family
54
+ assert_equal 'family', @family.name
55
+ end
56
+
57
+ should "yield itself" do
58
+ @container = container(:family) do |family|
59
+ family << widget(:mum_widget, 'mum')
60
+ end
61
+ assert_equal 2, @container.size
62
+ end
63
+
64
+ should "be aliased to #section for backward-compatibility" do
65
+ assert_kind_of ::Apotomo::ContainerWidget, section('family')
66
+ end
67
+ end
68
+ end