apotomo 1.1.4 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. data/CHANGES.textile +11 -0
  2. data/Rakefile +1 -1
  3. data/apotomo.gemspec +1 -1
  4. data/lib/apotomo/rails/controller_methods.rb +1 -8
  5. data/lib/apotomo/request_processor.rb +1 -1
  6. data/lib/apotomo/version.rb +1 -1
  7. data/lib/apotomo/widget.rb +13 -28
  8. data/lib/apotomo/widget/event_methods.rb +15 -24
  9. data/lib/apotomo/widget/tree_node.rb +10 -46
  10. data/lib/apotomo/widget_shortcuts.rb +39 -10
  11. data/test/{unit/apotomo_test.rb → apotomo_test.rb} +0 -0
  12. data/test/{unit/event_handler_test.rb → event_handler_test.rb} +4 -4
  13. data/test/{unit/event_methods_test.rb → event_methods_test.rb} +16 -16
  14. data/test/{unit/event_test.rb → event_test.rb} +1 -1
  15. data/test/{unit/javascript_generator_test.rb → javascript_generator_test.rb} +0 -0
  16. data/test/{unit/onfire_integration_test.rb → onfire_integration_test.rb} +3 -2
  17. data/test/rails/controller_methods_test.rb +0 -4
  18. data/test/rails/rails_integration_test.rb +58 -31
  19. data/test/rails/view_helper_test.rb +6 -4
  20. data/test/{unit/render_test.rb → render_test.rb} +6 -6
  21. data/test/{unit/request_processor_test.rb → request_processor_test.rb} +15 -10
  22. data/test/test_case_methods.rb +18 -5
  23. data/test/{unit/test_case_test.rb → test_case_test.rb} +0 -0
  24. data/test/test_helper.rb +0 -4
  25. data/test/tree_node_test.rb +19 -0
  26. data/test/widget_shortcuts_test.rb +70 -0
  27. data/test/{unit/widget_test.rb → widget_test.rb} +21 -49
  28. data/test/widgets/mouse/feed.html.erb +1 -1
  29. metadata +19 -19
  30. data/test/unit/widget_shortcuts_test.rb +0 -76
  31. data/test/widgets/mouse/posing.html.erb +0 -1
data/CHANGES.textile CHANGED
@@ -1,3 +1,14 @@
1
+ h2. 1.2.0
2
+
3
+ h3. Changes
4
+ * The @Widget.new@ constructor now expects the parent widget as first argument (except for the root widget, which still gets the damned ActionController instance). Nobody needed orphaned widgets so far so we decided to make it simpler. This makes the @#<<@ method a DSL-method, only.
5
+ * You can now access the root widget instance (or any other parent widget) in any subsequent @has_widgets@ block. This fixes "a famous issue":https://github.com/apotonick/apotomo/issues/34 and makes the @:passing@ option work as expected at every tree level.
6
+ * The @#widget@ shortcut method no longer returns a valid widget instance but a DSL-specific thing. Use the real constructor form if you need it right away (@MouseWidget.new(parent, :kid)@) or access the instance afterwards (@root[:kid]@).
7
+ * Removed the @after_add@ hook. Now that adding happens in the constructor, hook into @after_initialize@.
8
+ * Removed @#param@ in favor of @#options@.
9
+ * Removed @#emit@ in favor of @#render@.
10
+ * Removed @#remove_all!@ and @#remove_from_parent!@. Did you ever use these?
11
+
1
12
  h2. 1.1.4
2
13
 
3
14
  h3. Changes
data/Rakefile CHANGED
@@ -8,6 +8,6 @@ task :default => :test
8
8
 
9
9
  Rake::TestTask.new(:test) do |test|
10
10
  test.libs << 'test'
11
- test.test_files = FileList['test/unit/*_test.rb', 'test/rails/*_test.rb']# - ['test/rails/capture_test.rb']
11
+ test.test_files = FileList['test/*_test.rb', 'test/rails/*_test.rb']
12
12
  test.verbose = true
13
13
  end
data/apotomo.gemspec CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
21
21
 
22
22
  s.add_dependency "cells", ">= 3.6.7"
23
23
  s.add_dependency "onfire", "~> 0.2.0"
24
- s.add_dependency "hooks", "~> 0.1.3"
24
+ s.add_dependency "hooks", "~> 0.2.0"
25
25
 
26
26
  s.add_development_dependency "shoulda"
27
27
  s.add_development_dependency "rake"
@@ -48,7 +48,7 @@ module Apotomo
48
48
  return @apotomo_request_processor if @apotomo_request_processor
49
49
 
50
50
  # happens once per request:
51
- options = { :js_framework => Apotomo.js_framework || :prototype } # FIXME: remove :prototype
51
+ options = {:js_framework => Apotomo.js_framework}
52
52
 
53
53
  @apotomo_request_processor = Apotomo::RequestProcessor.new(self, options, self.class.has_widgets_blocks)
54
54
  end
@@ -84,13 +84,6 @@ module Apotomo
84
84
  end
85
85
 
86
86
  protected
87
-
88
- # TODO: remove me! only needed in widget_shortcuts.
89
- def parent_controller
90
- self
91
- end
92
-
93
-
94
87
  # Renders the page updates through an iframe. Copied from responds_to_parent,
95
88
  # see http://github.com/markcatley/responds_to_parent .
96
89
  def render_iframe_updates(page_updates)
@@ -12,7 +12,7 @@ module Apotomo
12
12
 
13
13
 
14
14
  def initialize(controller, options={}, has_widgets_blocks=[])
15
- @root = Widget.new(controller, 'root')
15
+ @root = Widget.new(controller, :root)
16
16
 
17
17
  attach_stateless_blocks_for(has_widgets_blocks, @root, controller)
18
18
 
@@ -1,3 +1,3 @@
1
1
  module Apotomo
2
- VERSION = '1.1.4'
2
+ VERSION = '1.2.0'
3
3
  end
@@ -39,7 +39,6 @@ module Apotomo
39
39
 
40
40
  DEFAULT_VIEW_PATHS = [
41
41
  File.join('app', 'widgets'),
42
- File.join('app', 'widgets', 'layouts')
43
42
  ]
44
43
 
45
44
  include Hooks
@@ -50,14 +49,11 @@ module Apotomo
50
49
  # Example:
51
50
  #
52
51
  # class MouseWidget < Apotomo::Widget
53
- # after_initialize :setup_cheese
54
- #
55
- # # we need @cheese in every state:
56
- # def setup_cheese(*)
52
+ # after_initialize do
57
53
  # @cheese = Cheese.find options[:cheese_id]
54
+ # end
58
55
  define_hook :after_initialize
59
56
  define_hook :has_widgets
60
- define_hook :after_add
61
57
 
62
58
  attr_writer :visible
63
59
 
@@ -73,32 +69,30 @@ module Apotomo
73
69
  helper Apotomo::Rails::ActionViewMethods
74
70
 
75
71
  abstract!
76
-
77
72
  undef :display # We don't want #display to be listed in #internal_methods.
78
73
 
79
74
  alias_method :widget_id, :name
80
75
 
81
-
82
- # Runs callbacks for +name+ hook in instance context.
83
- def run_widget_hook(name, *args)
84
- self.class.callbacks_for_hook(name).each { |blk| instance_exec(*args, &blk) }
85
- end
86
-
87
- def add_has_widgets_blocks(*)
88
- run_widget_hook(:has_widgets, self)
76
+ after_initialize do
77
+ run_hook :has_widgets, self
89
78
  end
90
- after_initialize :add_has_widgets_blocks
91
79
 
92
80
 
93
- def initialize(parent_controller, id, options={})
94
- super(parent_controller, options) # do that as long as cells do need a parent_controller.
95
-
81
+ def initialize(parent, id, options={})
82
+ super(parent, options) # TODO: do that as long as cells do need a parent_controller. remember to remove options for cells 3.7.
96
83
  @name = id
97
84
  @visible = true
98
85
 
86
+ setup_tree_node(parent)
87
+
99
88
  run_hook :after_initialize, self
100
89
  end
101
90
 
91
+ def parent_controller
92
+ # i hope we'll get rid of any parent_controller dependency, soon.
93
+ root? ? @parent_controller : root.parent_controller
94
+ end
95
+
102
96
  def visible?
103
97
  @visible
104
98
  end
@@ -132,15 +126,6 @@ module Apotomo
132
126
  super
133
127
  end
134
128
 
135
- alias_method :emit, :render
136
-
137
- def param(name)
138
- msg = "Deprecated. Use #options for widget constructor options or #params for request data."
139
- ActiveSupport::Deprecation.warn(msg)
140
- raise msg
141
- end
142
-
143
-
144
129
  # Returns the widget named +widget_id+ if it's a descendent or self.
145
130
  def find_widget(widget_id)
146
131
  find {|node| node.name.to_s == widget_id.to_s}
@@ -6,7 +6,19 @@ module Apotomo
6
6
  extend ActiveSupport::Concern
7
7
 
8
8
  included do
9
- after_initialize :add_class_event_handlers
9
+ after_initialize do
10
+ self.class.responds_to_event_options.each do |args|
11
+ type, options = args[0], args[1] || {}
12
+ target = self
13
+
14
+ if target_id = options[:passing]
15
+ target = root.find_widget(target_id)
16
+ options[:on] ||= widget_id
17
+ end
18
+
19
+ target.respond_to_event(type, options)
20
+ end
21
+ end
10
22
 
11
23
  inheritable_attr :responds_to_event_options
12
24
  self.responds_to_event_options = []
@@ -57,34 +69,18 @@ module Apotomo
57
69
  # Note that the observers are inherited. This allows deriving a widget class without having to redefine the
58
70
  # responds_to_event blocks.
59
71
  def responds_to_event(*options)
60
- # DISCUSS: this is a Hooks.declarative_attr candidate, too.
61
- return set_global_event_handler(*options) if options.dup.extract_options![:passing]
62
-
63
72
  responds_to_event_options << options
64
73
  end
65
-
66
- private
67
- # Adds an event handler to a non-local widget. Called in #responds_to_event when the
68
- # :passing option is set.
69
- #
70
- # This usually leads to something like
71
- # root.respond_to_event :click, :on => 'jerry'
72
- def set_global_event_handler(type, options)
73
- after_add do
74
- opts = options.reverse_merge(:on => widget_id)
75
- root.find_widget(opts.delete(:passing)).respond_to_event(type, opts)
76
- end
77
- end
78
74
  end
79
75
 
80
76
  # Same as #responds_to_event but executed on the widget instance, only.
81
77
  def respond_to_event(type, options={})
78
+ # DISCUSS: do we need the :once option? how could we avoid re-adding?
82
79
  options = options.reverse_merge(:once => true,
83
80
  :with => type,
84
- :on => self.name)
81
+ :on => widget_id)
85
82
 
86
83
  handler = InvokeEventHandler.new(:widget_id => options[:on], :state => options[:with])
87
-
88
84
  return if options[:once] and event_table.all_handlers_for(type, options[:from]).include?(handler)
89
85
 
90
86
  on(type, :call => handler, :from => options[:from])
@@ -113,10 +109,5 @@ module Apotomo
113
109
  def event_for(*args) # defined in Onfire: we want Apotomo::Event.
114
110
  Event.new(*args)
115
111
  end
116
-
117
- # Actually executes the #responds_to_event calls from the class on the instance.
118
- def add_class_event_handlers(*)
119
- self.class.responds_to_event_options.each { |options| respond_to_event(*options) }
120
- end
121
112
  end
122
113
  end
@@ -1,22 +1,17 @@
1
- # stolen from ... ? couldn't find the original lib on the net.
2
- ### TODO: insert copyright notice!
3
-
4
1
  module Apotomo
5
2
  module TreeNode
6
3
  include Enumerable
4
+ include Apotomo::WidgetShortcuts::DSL
7
5
 
8
6
  attr_reader :name, :childrenHash
9
7
  attr_accessor :parent
10
8
 
11
- def self.included(base)
12
- base.after_initialize :initialize_tree_node
13
- end
14
-
15
- def initialize_tree_node(*)
16
- root!
17
-
9
+ def setup_tree_node(parent)
10
+ @parent = nil
18
11
  @childrenHash = {}
19
- @children = []
12
+ @children = []
13
+
14
+ parent.add_widget(self) if parent.kind_of? Widget # TODO: as long as cells needs parent_controller.
20
15
  end
21
16
 
22
17
  # Print the string representation of this node.
@@ -25,26 +20,13 @@ module Apotomo
25
20
  " Children: #{children.length}" + " Total Nodes: #{size}"
26
21
  end
27
22
 
28
- # Convenience synonym for Tree#add method.
29
- # This method allows a convenient method to add
30
- # children hierarchies in the tree.
31
- # E.g. root << child << grand_child
32
- def <<(child)
33
- add(child)
34
- end
35
-
36
- # Adds the specified child node to the receiver node.
37
- # The child node's parent is set to be the receiver.
38
- # The child is added as the last child in the current
39
- # list of children for the receiver node.
40
- def add(child)
23
+ def add_widget(child) # TODO: rename #add, make private
41
24
  raise "Child already added" if @childrenHash.has_key?(child.name)
42
-
43
- @childrenHash[child.name] = child
25
+
26
+ @childrenHash[child.widget_id] = child
44
27
  @children << child
45
28
  child.parent = self
46
29
 
47
- child.run_widget_hook(:after_add, child, self)
48
30
  child
49
31
  end
50
32
 
@@ -59,23 +41,6 @@ module Apotomo
59
41
  child
60
42
  end
61
43
 
62
- # Removes this node from its parent. If this is the root node,
63
- # then does nothing.
64
- def remove_from_parent!
65
- @parent.remove!(self) unless root?
66
- end
67
-
68
- # Removes all children from the receiver node.
69
- def remove_all!
70
- for child in @children
71
- child.root!
72
- end
73
- @childrenHash.clear
74
- @children.clear
75
- self
76
- end
77
-
78
-
79
44
  # Private method which sets this node as a root node.
80
45
  def root!
81
46
  @parent = nil
@@ -127,7 +92,6 @@ module Apotomo
127
92
 
128
93
  # Pretty prints the tree starting with the receiver node.
129
94
  def printTree(tab = 0)
130
- puts((' ' * tab) + self.to_s)
131
95
  children {|child| child.printTree(tab + 4)}
132
96
  end
133
97
 
@@ -174,4 +138,4 @@ module Apotomo
174
138
  path.reverse.join("/")
175
139
  end
176
140
  end
177
- end
141
+ end
@@ -1,13 +1,15 @@
1
1
  module Apotomo
2
- # Shortcut methods for creating widget trees.
2
+ # Create widget trees using the #widget DSL.
3
3
  module WidgetShortcuts
4
4
  # Shortcut for creating an instance of <tt>class_name+"_widget"</tt> named +id+. Yields self.
5
+ # Note that this creates a proxy object, only. The actual widget is built not until you added
6
+ # it, e.g. using #<<.
5
7
  #
6
8
  # Example:
7
9
  #
8
- # widget(:comments)
10
+ # root << widget(:comments)
9
11
  #
10
- # will create a +CommentsWidget+ with id :comments.
12
+ # will create a +CommentsWidget+ with id :comments attached to +root+.
11
13
  #
12
14
  # widget(:comments, 'post-comments', :user => current_user)
13
15
  #
@@ -16,18 +18,45 @@ module Apotomo
16
18
  # You can also use namespaces.
17
19
  #
18
20
  # widget('jquery/tabs', 'panel')
19
- def widget(prefix, *args)
20
- options = args.extract_options!
21
- id = args.shift || prefix
22
-
23
- constant_for(prefix).new(parent_controller, id, options).tap do |object|
24
- yield object if block_given?
25
- end
21
+ #
22
+ # Add a block if you need to grab the created widget right away.
23
+ #
24
+ # root << widget(:comments) do |comments|
25
+ # comments.markdown!
26
+ # end
27
+ #
28
+ # Using #widget is just a shortcut, you can always use the constructor as well.
29
+ #
30
+ # CommentsWidget.new(root, :comments)
31
+ def widget(*args, &block)
32
+ FactoryProxy.new(*args, &block)
26
33
  end
27
34
 
35
+ class FactoryProxy
36
+ def initialize(prefix, *args, &block)
37
+ options = args.extract_options!
38
+ id = args.shift || prefix
39
+
40
+ @prefix, @id, @options, @block = prefix, id, options, block
41
+ end
42
+
43
+ def build(parent)
44
+ widget = constant_for(@prefix).new(parent, @id, @options)
45
+ @block.call(widget) if @block
46
+ widget
47
+ end
48
+
28
49
  private
29
50
  def constant_for(class_name) # TODO: use Cell.class_from_cell_name.
30
51
  "#{class_name}_widget".classify.constantize
31
52
  end
53
+ end
54
+
55
+ # Mixed into Widget.
56
+ module DSL
57
+ def <<(child)
58
+ child.build(self)
59
+ end
60
+ end
32
61
  end
33
62
  end
File without changes
@@ -6,18 +6,18 @@ class EventHandlerTest < Test::Unit::TestCase
6
6
 
7
7
  context "an abstract EventHandler" do
8
8
  should "push nil to root's ordered page_updates when #call'ed" do
9
- @mum = mouse_mock('mum')
10
- @mum << @kid = mouse_mock('kid')
9
+ @mum = mouse
10
+ @mum << mouse_mock(:kid)
11
11
 
12
12
  assert_equal 0, @mum.page_updates.size
13
13
 
14
- [@mum, @kid, @mum].each do |source|
14
+ [@mum, @mum[:kid], @mum].each do |source|
15
15
  Apotomo::EventHandler.new.call(Apotomo::Event.new(:squeak, source))
16
16
  end
17
17
 
18
18
  # order matters:
19
19
  assert_equal 3, @mum.page_updates.size
20
- assert_equal 0, @kid.page_updates.size
20
+ assert_equal 0, @mum[:kid].page_updates.size
21
21
  assert_equal(nil, @mum.page_updates[0])
22
22
  assert_equal(nil, @mum.page_updates[1])
23
23
  assert_equal(nil, @mum.page_updates[2])
@@ -18,9 +18,9 @@ class EventMethodsTest < Test::Unit::TestCase
18
18
  assert_equal ['be alerted', 'answer squeak'], @mum.list
19
19
  end
20
20
 
21
- should "make @mum just squeak back when @jerry squeaks" do
22
- @mum << @jerry = mouse_mock('jerry')
23
- @jerry.fire :squeak
21
+ should "make @mum just squeak back when jerry squeaks" do
22
+ @mum << mouse_mock(:jerry)
23
+ @mum[:jerry].fire :squeak
24
24
  assert_equal ['answer squeak'], @mum.list
25
25
  end
26
26
 
@@ -82,17 +82,17 @@ class EventMethodsTest < Test::Unit::TestCase
82
82
  responds_to_event :squeak, :passing => :root
83
83
  end
84
84
 
85
- @root = mouse_mock(:root)
85
+ @root = mouse(:root)
86
86
  end
87
87
 
88
88
  should "add handlers to root when called with :passing" do
89
- @root << AdolescentMouse.new(parent_controller, 'jerry')
89
+ AdolescentMouse.new(@root, 'jerry')
90
90
 
91
91
  assert_equal [handler('jerry', :squeak)], @root.event_table.all_handlers_for(:squeak, 'jerry')
92
92
  end
93
93
 
94
94
  should "inherit :passing handlers" do
95
- @root << Class.new(AdolescentMouse).new(parent_controller, 'jerry')
95
+ Class.new(AdolescentMouse).new(@root, 'jerry')
96
96
 
97
97
  assert_equal [handler('jerry', :squeak)], @root.event_table.all_handlers_for(:squeak, 'jerry')
98
98
  end
@@ -100,15 +100,15 @@ class EventMethodsTest < Test::Unit::TestCase
100
100
  end
101
101
 
102
102
  context "#responds_to_event in class context" do
103
- setup do
104
- class AdultMouse < MouseWidget
105
- responds_to_event :peep, :with => :answer_squeak
106
- end
107
- class BabyMouse < AdultMouse
108
- responds_to_event :peep
109
- responds_to_event :footsteps, :with => :squeak
110
- end
103
+ class AdultMouse < Apotomo::Widget
104
+ responds_to_event :peep, :with => :answer_squeak
105
+ end
106
+ class BabyMouse < AdultMouse
107
+ responds_to_event :peep
108
+ responds_to_event :footsteps, :with => :squeak
109
+ end
111
110
 
111
+ setup do
112
112
  @mum = AdultMouse.new(parent_controller, 'mum')
113
113
  end
114
114
 
@@ -117,8 +117,8 @@ class EventMethodsTest < Test::Unit::TestCase
117
117
  end
118
118
 
119
119
  should "inherit handlers" do
120
- @peep_handlers = BabyMouse.new(parent_controller, 'kid', :show).event_table.all_handlers_for(:peep, 'kid')
121
- assert_equal [handler('kid', :answer_squeak), handler('kid', :peep)], @peep_handlers
120
+ assert_equal [[:peep, {:with=>:answer_squeak}]], AdultMouse.responds_to_event_options
121
+ assert_equal [[:peep, {:with=>:answer_squeak}], [:peep], [:footsteps, {:with=>:squeak}]], BabyMouse.responds_to_event_options
122
122
  end
123
123
 
124
124
  should "not share responds_to_event options between different instances" do
@@ -21,7 +21,7 @@ class EventTest < Test::Unit::TestCase
21
21
  end
22
22
 
23
23
  should "respond to #to_s" do
24
- @event = Apotomo::Event.new(:footsteps, mouse_mock('mum'))
24
+ @event = Apotomo::Event.new(:footsteps, mouse('mum'))
25
25
  assert_equal "<Event :footsteps source=mum>", @event.to_s
26
26
  end
27
27
  end
@@ -5,8 +5,9 @@ class OnfireIntegrationTest < Test::Unit::TestCase
5
5
 
6
6
  context "including Onfire into the StatefulWidget it" do
7
7
  setup do
8
- @mum = mouse_mock('mum')
9
- @mum << @kid = mouse_mock('kid')
8
+ @mum = mouse('mum')
9
+ @mum << mouse_mock(:kid)
10
+ @kid = @mum[:kid]
10
11
  end
11
12
 
12
13
  should "respond to #root" do
@@ -22,10 +22,6 @@ class ControllerMethodsTest < ActionController::TestCase
22
22
  end
23
23
  end
24
24
 
25
- should "respond to parent_controller" do
26
- assert_equal @controller, @controller.send(:parent_controller)
27
- end
28
-
29
25
  context "invoking #has_widgets" do
30
26
  setup do
31
27
  @controller.class.has_widgets do |root|
@@ -3,63 +3,90 @@ require 'test_helper'
3
3
  class RailsIntegrationTest < ActionController::TestCase
4
4
  include Apotomo::TestCaseMethods::TestController
5
5
 
6
- def simulate_request!
7
- @controller.instance_eval { @apotomo_request_processor = nil }
6
+ class KidWidget < MouseWidget
7
+ responds_to_event :squeak, :passing => :root
8
+
9
+ def feed
10
+ render # invokes #url_for_event.
11
+ end
12
+
13
+ def squeak
14
+ render :text => "squeak!"
15
+ end
8
16
  end
9
17
 
18
+
19
+ class MumWidget < MouseWidget
20
+ responds_to_event :squeak
21
+ responds_to_event :sniff
22
+
23
+ has_widgets do |me|
24
+ me << widget("rails_integration_test/kid", :kid)
25
+ end
26
+
27
+ def eat
28
+ render
29
+ end
30
+
31
+ def make_me_squeak
32
+ render
33
+ end
34
+
35
+ def squeak(evt)
36
+ render :text => evt.data
37
+ end
38
+
39
+ def sniff(evt)
40
+ render :text => "<b>sniff sniff</b>"
41
+ end
42
+
43
+ def child
44
+ render :text => render_widget(:kid, :feed)
45
+ end
46
+ end
47
+
48
+
10
49
  context "ActionController" do
11
50
  setup do
12
- @mum = mum = MouseWidget.new(parent_controller, 'mum', :eating)
13
- @mum.instance_eval do
14
- def eating; render; end
15
- end
16
-
17
- @mum.respond_to_event :squeak
18
-
19
51
  @controller.class.has_widgets do |root|
20
- root << mum
52
+ MumWidget.new(root, 'mum')
21
53
  end
22
54
 
23
55
  @controller.instance_eval do
24
56
  def mum
25
- render :text => render_widget('mum', :eat)
57
+ render :text => render_widget('mum', params[:state])
26
58
  end
27
59
  end
28
60
  end
29
61
 
30
62
  should "provide the rails view helpers in state views" do
31
- @mum.instance_eval do
32
- def eat; render :view => :make_me_squeak; end
33
- end
34
-
35
- get 'mum'
63
+ get 'mum', :state => :make_me_squeak
36
64
  assert_select "a", "mum"
37
65
  end
38
66
 
39
- should "pass the event with all params data as state-args" do
40
- @mum.instance_eval do
41
- def squeak(evt); render :text => evt.data; end
67
+ context "nested widgets" do
68
+ should "render" do
69
+ get 'mum', :state => :child
70
+ assert_equal "/barn/render_event_response?source=kid&amp;type=click\n", @response.body
42
71
  end
43
72
 
73
+ should "process events" do
74
+ get 'render_event_response', :source => 'root', :type => :squeak
75
+ assert_equal "squeak!", @response.body
76
+ end
77
+ end
78
+
79
+ should "pass the event with all params data as state-args" do
44
80
  get 'render_event_response', :source => 'mum', :type => :squeak, :pitch => :high
45
- assert_equal "{\"source\"=>\"mum\", \"type\"=>\"squeak\", \"pitch\"=>\"high\", \"controller\"=>\"barn\", \"action\"=>\"render_event_response\"}", @response.body
81
+ assert_equal "{\"source\"=>\"mum\", \"type\"=>\"squeak\", \"pitch\"=>\"high\", \"controller\"=>\"barn\", \"action\"=>\"render_event_response\"}\nsqueak!", @response.body
46
82
  end
47
83
 
48
84
  should "render updates to the parent window for an iframe request" do
49
- @mum.instance_eval do
50
- def squeak(evt); render :text => "<b>SQUEAK!</b>"; end
51
- end
52
-
53
- get 'mum'
54
- assert_response :success
55
-
56
- simulate_request!
57
-
58
- get 'render_event_response', :source => 'mum', :type => :squeak, :apotomo_iframe => true
85
+ get 'render_event_response', :source => 'mum', :type => :sniff, :apotomo_iframe => true
59
86
 
60
87
  assert_response :success
61
88
  assert_equal 'text/html', @response.content_type
62
- assert_equal "<html><body><script type='text/javascript' charset='utf-8'>\nvar loc = document.location;\nwith(window.parent) { setTimeout(function() { window.eval('<b>SQUEAK!<\\/b>'); window.loc && loc.replace('about:blank'); }, 1) }\n</script></body></html>", @response.body
89
+ assert_equal "<html><body><script type='text/javascript' charset='utf-8'>\nvar loc = document.location;\nwith(window.parent) { setTimeout(function() { window.eval('<b>sniff sniff<\\/b>'); window.loc && loc.replace('about:blank'); }, 1) }\n</script></body></html>", @response.body
63
90
  end
64
91
 
65
92
 
@@ -66,14 +66,16 @@ class ViewHelperTest < Apotomo::TestCase
66
66
  end
67
67
 
68
68
  should "respond to #render_widget" do
69
- mum = mouse_mock
70
- mum << mouse_mock('kid')
69
+ mum = mouse
70
+ MouseWidget.new(mum, :kid)
71
+
71
72
  assert_equal("<div id=\"kid\">burp!</div>\n", in_view(mum){ render_widget 'kid', :eat })
72
73
  end
73
74
 
74
75
  should "respond to #children" do
75
- mum = mouse_mock
76
- mum << mouse_mock('kid')
76
+ mum = mouse
77
+ MouseWidget.new(mum, :kid)
78
+
77
79
  assert_equal("<div id=\"kid\">burp!</div>\n", in_view(mum) do
78
80
  children.inject("") { |html, child| html += render_widget(child, :eat) }.html_safe
79
81
  end)
@@ -5,7 +5,7 @@ class RenderTest < ActionView::TestCase
5
5
 
6
6
  context "#render" do
7
7
  setup do
8
- @mum = mouse_mock('mum', :eating)
8
+ @mum = mouse('mum')
9
9
  end
10
10
 
11
11
  should "per default display the state content framed in a div" do
@@ -31,7 +31,7 @@ class RenderTest < ActionView::TestCase
31
31
  end
32
32
 
33
33
  should "expose its instance variables in the rendered view" do
34
- @mum = mouse_mock('mum', :educate) do
34
+ @mum = mouse('mum') do
35
35
  def educate
36
36
  @who = "the cat"
37
37
  @what = "run away"
@@ -41,12 +41,12 @@ class RenderTest < ActionView::TestCase
41
41
  assert_equal 'If you see the cat do run away!', @mum.invoke(:educate)
42
42
  end
43
43
 
44
- context "with #emit" do
44
+ context "with #render" do
45
45
  context "and :text" do
46
46
  setup do
47
47
  @mum.instance_eval do
48
48
  def squeak
49
- emit :text => "squeak();"
49
+ render :text => "squeak();"
50
50
  end
51
51
  end
52
52
  end
@@ -60,7 +60,7 @@ class RenderTest < ActionView::TestCase
60
60
  setup do
61
61
  @mum.instance_eval do
62
62
  def squeak
63
- emit
63
+ render
64
64
  end
65
65
  end
66
66
  end
@@ -74,7 +74,7 @@ class RenderTest < ActionView::TestCase
74
74
  setup do
75
75
  @mum.instance_eval do
76
76
  def squeak
77
- emit :view => :eating
77
+ render :view => :eating
78
78
  end
79
79
  end
80
80
  end
@@ -72,8 +72,9 @@ class RequestProcessorTest < ActiveSupport::TestCase
72
72
  def squeak; render :text => "squeak!"; end
73
73
  end
74
74
 
75
- procs = [Proc.new{ |root,controller|
76
- root << widget(:mouse, 'mum') << KidWidget.new(parent_controller, 'kid', :squeak)
75
+ procs = [Proc.new{ |root|
76
+ root << widget(:mouse, 'mum')
77
+ KidWidget.new(root['mum'], 'kid')
77
78
  }]
78
79
 
79
80
  @processor = Apotomo::RequestProcessor.new(parent_controller, {:js_framework => :prototype}, procs)
@@ -138,36 +139,40 @@ class RequestProcessorHooksTest < ActiveSupport::TestCase
138
139
 
139
140
  context "Hooks in RequestProcessor" do
140
141
  setup do
142
+ @kid = mouse_mock(:kid)
141
143
  @class = Class.new(Apotomo::RequestProcessor)
144
+ @class.instance_eval do
145
+ def kid=(kid); @kid=kid end
146
+ def kid; @kid end
147
+ end
148
+ @class.kid = @kid
142
149
  end
143
150
 
144
151
  context ":after_initialize hook" do
145
152
  should "be called after the has_widgets blocks invokation" do
146
- @k = mouse_mock("kid")
147
153
  @class.after_initialize do |r|
148
- r.root["mum"] << @k
154
+ r.root[:mum] << self.class.kid # requires that :mum is there, yet.
149
155
  end
150
156
 
151
157
  @r = @class.new(parent_controller, {},
152
- [Proc.new { |root| root << widget(:mouse, 'mum') }])
158
+ [Proc.new { |root| root << widget(:mouse, :mum) }])
153
159
 
154
- assert_equal @r.root["mum"]["kid"], @k
160
+ assert @r.root[:mum][:kid]
155
161
  end
156
162
  end
157
163
 
158
164
  context ":after_fire hook" do
159
165
  should "be called in #process_for after fire" do
160
- @k = mouse_mock("kid")
161
166
  @class.after_fire do |r|
162
- r.root["mum"] << @k = mouse_mock("kid")
167
+ r.root[:mum] << self.class.kid
163
168
  end
164
169
 
165
170
  # DISCUSS: maybe add a trigger test here?
166
171
  @r = @class.new(parent_controller, {},
167
- [Proc.new { |root| root << widget(:mouse, 'mum') }])
172
+ [Proc.new { |root| root << widget(:mouse, :mum) }])
168
173
  @r.process_for(:source => "root", :type => :noop) # calls ~after_fire.
169
174
 
170
- assert_equal @k, @r.root["mum"]["kid"]
175
+ assert @r.root[:mum][:kid]
171
176
  end
172
177
  end
173
178
  end
@@ -1,10 +1,22 @@
1
1
  module Apotomo
2
2
  module TestCaseMethods
3
+ def root_mock
4
+ MouseWidget.new(parent_controller, :root)
5
+ end
6
+
7
+ def mouse(id=nil, &block)
8
+ MouseWidget.new(parent_controller, id || :mouse).tap do |widget|
9
+ widget.instance_eval &block if block_given?
10
+ end
11
+ end
12
+
13
+
3
14
  # Provides a ready-to-use mouse widget instance.
4
15
  def mouse_mock(id='mouse', opts={}, &block)
5
- mouse = MouseWidget.new(parent_controller, id, opts)
6
- mouse.instance_eval &block if block_given?
7
- mouse
16
+ #mouse = MouseWidget.new(parent_controller, id, opts)
17
+ #mouse.instance_eval &block if block_given?
18
+ widget(:mouse, id, opts)
19
+ #mouse
8
20
  end
9
21
 
10
22
  def mouse_class_mock(&block)
@@ -14,8 +26,9 @@ module Apotomo
14
26
  end
15
27
 
16
28
  def mum_and_kid!
17
- @mum = mouse_mock('mum')
18
- @mum << @kid = mouse_mock('kid')
29
+ @mum = mouse('mum')
30
+ @kid = MouseWidget.new(@mum, 'kid')
31
+
19
32
 
20
33
  @mum.respond_to_event :squeak, :with => :answer_squeak
21
34
  @mum.respond_to_event :squeak, :from => 'kid', :with => :alert
File without changes
data/test/test_helper.rb CHANGED
@@ -40,10 +40,6 @@ module Farm
40
40
  end
41
41
  end
42
42
 
43
- class MouseWidget < Apotomo::Widget
44
- end
45
-
46
-
47
43
  class MouseWidget < Apotomo::Widget
48
44
  def squeak
49
45
  render :text => "squeak!"
@@ -0,0 +1,19 @@
1
+ require 'test_helper'
2
+
3
+ class TreeNodeTest < ActiveSupport::TestCase
4
+ context "initialization" do
5
+ setup do
6
+
7
+ end
8
+
9
+ should "return true for #root? without parent" do
10
+ assert MouseWidget.new(nil, :mum).root?
11
+ end
12
+
13
+ should "return false for #root? with parent" do
14
+ @mum = MouseWidget.new(nil, :mum)
15
+ assert_not MouseWidget.new(@mum, :kid).root?
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,70 @@
1
+ require 'test_helper'
2
+
3
+ class MumWidget < MouseWidget; end
4
+ class MouseTabsWidget;end
5
+
6
+ class WidgetShortcutsTest < Test::Unit::TestCase
7
+ context "FactoryProxy" do
8
+ setup do
9
+ @factory = Apotomo::WidgetShortcuts::FactoryProxy
10
+ end
11
+
12
+ context "#constant_for" do
13
+ setup do
14
+ @dsl = @factory.new(:class, :id)
15
+ end
16
+
17
+ should "constantize symbols" do
18
+ assert_equal MouseWidget, @dsl.send(:constant_for, :mouse)
19
+ end
20
+
21
+ should "not try to singularize the widget class" do
22
+ assert_equal MouseTabsWidget, @dsl.send(:constant_for, :mouse_tabs)
23
+ end
24
+ end
25
+
26
+ context "#widget and #<<" do
27
+ setup do
28
+ @root = Apotomo::Widget.new(nil, :root)
29
+ end
30
+
31
+ context "with all arguments" do
32
+ should "create a MumWidget instance with options" do
33
+ proxy = widget(:mum, :mummy, :eating, :color => 'grey', :type => :hungry)
34
+ @root << proxy
35
+
36
+ assert_kind_of MumWidget, @root[:mummy]
37
+ assert_equal :mummy, @root[:mummy].name
38
+ assert_equal({:color => "grey", :type => :hungry}, @root[:mummy].options)
39
+ end
40
+ end
41
+
42
+ should "not set options with 2 arguments" do
43
+ @root << widget(:mum, :mummy)
44
+ @mum = @root[:mummy]
45
+
46
+ assert_kind_of MumWidget, @mum
47
+ assert_equal :mummy, @mum.widget_id
48
+ assert_equal({}, @mum.options)
49
+ end
50
+
51
+ should "set defaults with prefix, only" do
52
+ @root << widget(:mum)
53
+ @mum = @root[:mum]
54
+
55
+ assert_kind_of MumWidget, @mum
56
+ assert_equal :mum, @mum.name
57
+ assert_equal({}, @mum.options)
58
+ end
59
+
60
+ should "yield itself" do
61
+ ficken = widget(:mum) do |mum|
62
+ mum << widget(:mouse, :kid)
63
+ end
64
+ @root << ficken
65
+ assert_equal 2, @root[:mum].size
66
+ assert_kind_of MouseWidget, @root[:mum][:kid]
67
+ end
68
+ end
69
+ end
70
+ end
@@ -14,51 +14,27 @@ class WidgetTest < ActiveSupport::TestCase
14
14
  setup do
15
15
  @mum = Class.new(MouseWidget) do
16
16
  has_widgets do |me|
17
- me << widget(:mouse, 'baby')
17
+ me << widget(:mouse, :baby)
18
+ #MouseWidget.new(me, :baby) # this is also possible.
18
19
  end
19
20
  end.new(@controller, 'mum')
20
21
 
21
- @kid = Class.new(@mum.class).new(@controller, 'mum', :squeak)
22
+ @kid = Class.new(@mum.class).new(@controller, 'mum')
22
23
  end
23
24
 
24
25
  should "setup the widget family at creation time" do
25
26
  assert_equal 1, @mum.children.size
26
- assert_kind_of Apotomo::Widget, @mum['baby']
27
+ assert_kind_of MouseWidget, @mum[:baby]
27
28
  end
28
29
 
29
30
  should "inherit trees for now" do
30
31
  assert_equal 1, @mum.children.size
31
- assert_kind_of Apotomo::Widget, @mum['baby']
32
+ assert_kind_of MouseWidget, @mum[:baby]
32
33
  end
33
34
  end
34
35
 
35
- context "Widget.after_add" do
36
- setup do
37
- @mum = Class.new(MouseWidget) do
38
- after_add do |me, parent|
39
- parent << widget(:mouse, 'kid', :squeak)
40
- end
41
- end.new(@controller, 'mum', :squeak)
42
-
43
- @root = mouse_mock('root')
44
- end
45
-
46
- should "be invoked after mum is added" do
47
- assert_equal [], @root.children
48
- @root << @mum
49
-
50
- assert_equal ['mum', 'kid'], @root.children.collect { |w| w.name }
51
- end
52
-
53
- should "inherit callbacks" do
54
- @berry = Class.new(@mum.class).new(@controller, 'berry', :squeak)
55
- @root << @berry
56
-
57
- assert_equal ['berry', 'kid'], @root.children.collect { |w| w.name }
58
- end
59
- end
60
-
61
- context "A stateless widget" do
36
+
37
+ context "A widget" do
62
38
  setup do
63
39
  @mum = Apotomo::Widget.new(@controller, 'mum', :squeak)
64
40
  end
@@ -119,22 +95,18 @@ class WidgetTest < ActiveSupport::TestCase
119
95
  assert_respond_to @mum, :widget
120
96
  end
121
97
 
122
- should "respond to #parent_controller" do
98
+ should "respond to #parent_controller and return the AC in root" do
99
+ @mum << mouse_mock(:kid)
123
100
  assert_equal @controller, @mum.parent_controller
101
+ assert_equal @controller, @mum[:kid].parent_controller
124
102
  end
125
103
 
126
104
  should "alias #widget_id to #name" do
127
105
  assert_equal @mum.name, @mum.widget_id
128
106
  end
129
107
 
130
- should "mark #param as deprecated" do
131
- assert_raises RuntimeError do
132
- @mum.param(:volume)
133
- end
134
- end
135
-
136
108
  should "respond to DEFAULT_VIEW_PATHS" do
137
- assert_equal ["app/widgets", "app/widgets/layouts"], Apotomo::Widget::DEFAULT_VIEW_PATHS
109
+ assert_equal ["app/widgets"], Apotomo::Widget::DEFAULT_VIEW_PATHS
138
110
  end
139
111
 
140
112
  should "respond to .view_paths" do
@@ -167,47 +139,47 @@ end
167
139
 
168
140
  class RenderWidgetTest < ActiveSupport::TestCase
169
141
  include Apotomo::TestCaseMethods::TestController
170
-
142
+
171
143
  context "#render_widget" do
172
144
  should "allow passing widget id" do
173
- assert_equal "squeak!", mouse_mock.render_widget('mouse', :squeak)
145
+ assert_equal "squeak!", mouse.render_widget('mouse', :squeak)
174
146
  end
175
147
 
176
148
  should "allow passing widget instance" do
177
- assert_equal 'squeak!', mouse_mock.render_widget(mouse_mock('mum'), :squeak)
149
+ assert_equal 'squeak!', mouse.render_widget(mouse(:mum), :squeak)
178
150
  end
179
151
 
180
152
  should "use :display as standard state" do
181
- mum = mouse_mock('Mum') do
153
+ mum = mouse('Mum') do
182
154
  def display
183
155
  render :text => "#{widget_id}, that's me!"
184
156
  end
185
157
  end
186
158
 
187
- assert_equal "Mum, that's me!", mouse_mock.render_widget(mum)
159
+ assert_equal "Mum, that's me!", mouse.render_widget(mum)
188
160
  end
189
161
 
190
162
  should "raise an exception when a non-existent widget id is passed" do
191
163
  e = assert_raises RuntimeError do
192
- mouse_mock.render_widget('mummy')
164
+ mouse.render_widget('mummy')
193
165
  end
194
166
 
195
167
  assert_equal "Couldn't render non-existent widget `mummy`", e.message
196
168
  end
197
169
 
198
170
  should "pass options as state-args" do
199
- mum = mouse_mock do
171
+ mum = mouse do
200
172
  def display(color="grey")
201
173
  render :text => "I'm #{color}"
202
174
  end
203
175
  end
204
176
 
205
- assert_equal("I'm grey", mouse_mock.render_widget(mum), "default value in state-arg didn't work")
206
- assert_equal("I'm black", mouse_mock.render_widget(mum, :display, "black"))
177
+ assert_equal("I'm grey", mouse.render_widget(mum), "default value in state-arg didn't work")
178
+ assert_equal("I'm black", mouse.render_widget(mum, :display, "black"))
207
179
  end
208
180
 
209
181
  should "use #find_widget from self to find the passed widget id" do
210
- mum = mouse_mock('mum') << mouse_mock(:kid)
182
+ mum = mouse << mouse_mock(:kid)
211
183
 
212
184
  assert_equal "<div id=\"kid\">burp!</div>\n", mum.render_widget(:kid, :eat)
213
185
  end
@@ -1 +1 @@
1
- <%= rendered_children.collect{|v| v.last}.join("\n")
1
+ <%= url_for_event :click %>
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 1
7
- - 1
8
- - 4
9
- version: 1.1.4
7
+ - 2
8
+ - 0
9
+ version: 1.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Nick Sutterer
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-09-28 00:00:00 +02:00
17
+ date: 2011-10-12 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -57,9 +57,9 @@ dependencies:
57
57
  - !ruby/object:Gem::Version
58
58
  segments:
59
59
  - 0
60
- - 1
61
- - 3
62
- version: 0.1.3
60
+ - 2
61
+ - 0
62
+ version: 0.2.0
63
63
  type: :runtime
64
64
  version_requirements: *id003
65
65
  - !ruby/object:Gem::Dependency
@@ -176,6 +176,7 @@ files:
176
176
  - lib/generators/templates/widget.rb
177
177
  - lib/generators/templates/widget_test.rb
178
178
  - lib/generators/test_unit/widget_generator.rb
179
+ - test/apotomo_test.rb
179
180
  - test/dummy/Rakefile
180
181
  - test/dummy/app/controllers/application_controller.rb
181
182
  - test/dummy/app/helpers/application_helper.rb
@@ -201,30 +202,29 @@ files:
201
202
  - test/dummy/public/500.html
202
203
  - test/dummy/public/favicon.ico
203
204
  - test/dummy/public/stylesheets/.gitkeep
205
+ - test/event_handler_test.rb
206
+ - test/event_methods_test.rb
207
+ - test/event_test.rb
208
+ - test/javascript_generator_test.rb
209
+ - test/onfire_integration_test.rb
204
210
  - test/rails/caching_test.rb
205
211
  - test/rails/controller_methods_test.rb
206
212
  - test/rails/rails_integration_test.rb
207
213
  - test/rails/view_helper_test.rb
208
214
  - test/rails/widget_generator_test.rb
215
+ - test/render_test.rb
216
+ - test/request_processor_test.rb
209
217
  - test/test_case_methods.rb
218
+ - test/test_case_test.rb
210
219
  - test/test_helper.rb
211
- - test/unit/apotomo_test.rb
212
- - test/unit/event_handler_test.rb
213
- - test/unit/event_methods_test.rb
214
- - test/unit/event_test.rb
215
- - test/unit/javascript_generator_test.rb
216
- - test/unit/onfire_integration_test.rb
217
- - test/unit/render_test.rb
218
- - test/unit/request_processor_test.rb
219
- - test/unit/test_case_test.rb
220
- - test/unit/widget_shortcuts_test.rb
221
- - test/unit/widget_test.rb
220
+ - test/tree_node_test.rb
221
+ - test/widget_shortcuts_test.rb
222
+ - test/widget_test.rb
222
223
  - test/widgets/mouse/eat.erb
223
224
  - test/widgets/mouse/eating.html.erb
224
225
  - test/widgets/mouse/educate.html.erb
225
226
  - test/widgets/mouse/feed.html.erb
226
227
  - test/widgets/mouse/make_me_squeak.html.erb
227
- - test/widgets/mouse/posing.html.erb
228
228
  - test/widgets/mouse/snuggle.html.erb
229
229
  has_rdoc: true
230
230
  homepage: http://github.com/apotonick/apotomo
@@ -1,76 +0,0 @@
1
- require 'test_helper'
2
-
3
- class MumWidget < MouseWidget; end
4
- class MouseTabsWidget;end
5
-
6
- class WidgetShortcutsTest < Test::Unit::TestCase
7
- include Apotomo::TestCaseMethods::TestController
8
-
9
- context "#constant_for" do
10
- should "constantize symbols" do
11
- assert_equal MumWidget, constant_for(:mum)
12
- end
13
-
14
- should "not try to singularize the widget class" do
15
- assert_equal MouseTabsWidget, constant_for(:mouse_tabs)
16
- end
17
- end
18
-
19
- context "#widget" do
20
- context "with all arguments" do
21
- setup do
22
- @mum = widget(:mum, 'mum', :eating, :color => 'grey', :type => :hungry)
23
- end
24
-
25
- should "create a MumWidget instance" do
26
- assert_kind_of MumWidget, @mum
27
- assert_equal 'mum', @mum.name
28
- end
29
-
30
- should "accept options" do
31
- assert_equal({:color => "grey", :type => :hungry}, @mum.options)
32
- end
33
- end
34
-
35
- context "with 3 arguments and no options" do
36
- should "not set options" do
37
- @mum = widget(:mum, 'mum', :squeak)
38
- assert_kind_of MumWidget, @mum
39
- assert_equal 'mum', @mum.name
40
- assert_equal({}, @mum.options)
41
- end
42
- end
43
-
44
- context "with class and id" do
45
- setup do
46
- @mum = widget(:mum, 'mummy')
47
- end
48
-
49
- should "create a MumWidget instance" do
50
- assert_kind_of MumWidget, @mum
51
- assert_equal 'mummy', @mum.name
52
- end
53
- end
54
-
55
- context "with class, only" do
56
- setup do
57
- @mum = widget(:mum)
58
- end
59
-
60
- should "create a MumWidget instance named :mum" do
61
- assert_kind_of MumWidget, @mum
62
- assert_equal :mum, @mum.name
63
- end
64
- end
65
-
66
-
67
- should "yield itself" do
68
- @mum = widget(:mum, 'mum') do |mum|
69
- assert_kind_of MumWidget, mum
70
- mum << widget(:mum, 'kid')
71
- end
72
- assert_equal 2, @mum.size
73
- assert_kind_of MumWidget, @mum['kid']
74
- end
75
- end
76
- end
@@ -1 +0,0 @@
1
- <%= rendered_children.collect{|e| e.last}.join("") %>