apotomo 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGES.textile ADDED
@@ -0,0 +1,8 @@
1
+ h2. 1.0.2
2
+
3
+ h3. Changes
4
+ * removals from ViewHelper: #trigger_event, #form_to_event and friends as they use deprecated Rails helpers.
5
+
6
+ h3. Bugfixes
7
+ * Widget#fire now accepts payload data for the fired event.
8
+ * triggered states now receive the event object if they expect one argument.
data/Gemfile CHANGED
@@ -1,9 +1,12 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- gem "rails", "~> 3.0.0"
4
- gem "cells", "~> 3.4"
5
- gem "onfire"
6
- gem "hooks", "~> 0.1.3"
3
+ gem "rails", "~> 3.0"
4
+ #gem "rails", :path => "/home/nick/projects/rayls"
5
+
6
+ gem "cells", "~> 3.4"
7
+ gem "onfire", "~> 0.1.1"
8
+ gem "hooks", "~> 0.1.3"
9
+
7
10
 
8
11
 
9
12
  gem "jeweler"
data/README.rdoc CHANGED
@@ -22,7 +22,7 @@ Easy as hell.
22
22
 
23
23
  === Rails 3
24
24
 
25
- gem install apotomo --pre
25
+ gem install apotomo
26
26
 
27
27
  === Rails 2.3
28
28
 
data/Rakefile CHANGED
@@ -34,7 +34,7 @@ Jeweler::Tasks.new do |spec|
34
34
  spec.test_files = FileList["test/**/*"] - FileList["test/dummy/tmp", "test/dummy/tmp/**/*", "test/dummy/log/*"]
35
35
 
36
36
  spec.add_dependency 'cells', '~> 3.4.2'
37
- spec.add_dependency 'rails', '>= 3.0.0'
37
+ spec.add_dependency 'rails', '~> 3.0.0'
38
38
  spec.add_dependency 'onfire', '>= 0.1.0'
39
39
  spec.add_dependency 'hooks', '~> 0.1.3'
40
40
  end
@@ -2,19 +2,19 @@ require 'apotomo/event_handler'
2
2
 
3
3
  module Apotomo
4
4
  # Introduces event-processing functions into the StatefulWidget.
5
-
6
5
  module EventMethods
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ after_initialize :add_class_event_handlers
10
+ end
11
+
7
12
  attr_writer :page_updates
8
- # Replacement for the EventProcessor singleton queue.
13
+
9
14
  def page_updates
10
15
  @page_updates ||= []
11
16
  end
12
17
 
13
- def self.included(base)
14
- base.extend(ClassMethods)
15
- base.after_initialize :add_class_event_handlers
16
- end
17
-
18
18
  def add_class_event_handlers(*)
19
19
  self.class.responds_to_event_options.each { |options| respond_to_event(*options) }
20
20
  end
@@ -34,66 +34,55 @@ module Apotomo
34
34
  # state, which implies an update of the invoked widget.
35
35
  #
36
36
  # You may configure the event handler with the following <tt>options</tt>:
37
- # :with => (required) the state to invoke on the target widget
37
+ # :with => (optional) the state to invoke on the target widget, defaults to +type+.
38
38
  # :on => (optional) the targeted widget's id, defaults to <tt>self.name</tt>
39
39
  # :from => (optional) the source id of the widget that triggered the event, defaults to any widget
40
40
  #
41
41
  # Example:
42
42
  #
43
- # trap = cell(:input_field, :smell_like_cheese, 'mouse_trap')
43
+ # trap = widget(:trap, :charged, 'mouse_trap')
44
44
  # trap.respond_to_event :mouseOver, :with => :catch_mouse
45
45
  #
46
- # This would instruct <tt>trap</tt> to catch a <tt>:mouseOver</tt> event from any widget (including itself) and
46
+ # This would instruct +trap+ to catch a <tt>:mouseOver</tt> event from any widget (including itself) and
47
47
  # to invoke the state <tt>:catch_mouse</tt> on itself as trigger.
48
48
  #
49
49
  #
50
- # hunter = cell(:form, :hunt_for_mice, 'my_form')
51
- # hunter << cell(:input_field, :smell_like_cheese, 'mouse_trap')
52
- # hunter << cell(:text_area, :stick_like_honey, 'bear_trap')
50
+ # hunter = widget(:form, :hunt_for_mice, 'my_form')
51
+ # hunter << widget(:input_field, :smell_like_cheese, 'mouse_trap')
52
+ # hunter << widget(:text_area, :stick_like_honey, 'bear_trap')
53
53
  # hunter.respond_to_event :captured, :from => 'mouse_trap', :with => :refill_cheese, :on => 'mouse_trap'
54
54
  #
55
55
  # As both the bear- and the mouse trap can trigger a <tt>:captured</tt> event the later <tt>respond_to_event</tt>
56
56
  # would invoke <tt>:refill_cheese</tt> on the <tt>mouse_trap</tt> widget as soon as this and only this widget fired.
57
57
  # It is important to understand the <tt>:from</tt> parameter as it filters the event source - it wouldn't make
58
- # sense to refill the mouse trap if the bear trap snapped, would it?
59
-
60
- def respond_to_event(type, options)
61
- options[:once] = true if options[:once].nil?
58
+ # sense to refill the mouse trap if the bear trap snapped, would it?
59
+ def respond_to_event(type, options={})
60
+ options.reverse_merge!( :once => true,
61
+ :with => type,
62
+ :on => self.name )
62
63
 
63
- handler_opts = {}
64
- handler_opts[:widget_id] = options[:on] || self.name
65
- handler_opts[:state] = options[:with]
66
-
67
- handler = InvokeEventHandler.new(handler_opts)
64
+ handler = InvokeEventHandler.new(:widget_id => options[:on], :state => options[:with])
68
65
 
69
66
  return if options[:once] and event_table.all_handlers_for(type, options[:from]).include?(handler)
70
67
 
71
68
  on(type, :do => handler, :from => options[:from])
72
69
  end
73
70
 
71
+ # Fire an event of +type+ and let it bubble up. You may add arbitrary payload data to the event.
72
+ #
73
+ # Example:
74
+ #
75
+ # trigger(:dropped, :area => 59)
76
+ #
77
+ # which can be queried in a triggered state.
78
+ #
79
+ # def on_drop(event)
80
+ # if event.data[:area] == 59
74
81
  def trigger(*args)
75
82
  fire(*args)
76
83
  end
77
84
 
78
- # Invokes <tt>state</tt> on the widget <em>and</end> updates itself on the page. This should
79
- # never be called from outside but in setters when some internal value changed and must be
80
- # displayed instantly.
81
- #
82
- # Implements the following pattern (TODO: remove example as soon as invoke! proofed):
83
- #
84
- # def title=(str)
85
- # @title = str
86
- # peek(:update, self.name, :display, self.name)
87
- # trigger(:update)
88
- # end
89
- def invoke!(state)
90
- ### TODO: encapsulate in PageUpdateQueue:
91
- Apotomo::EventProcessor.instance.processed_handlers << [name, invoke(:state)]
92
- end
93
-
94
-
95
-
96
- protected
85
+ protected
97
86
  # Get all handlers from self for the passed event (overriding Onfire#local_event_handlers).
98
87
  def local_event_handlers(event)
99
88
  event_table.all_handlers_for(event.type, event.source.name) # we key with widget_id.
@@ -10,13 +10,7 @@ module Apotomo
10
10
  def process_event(event)
11
11
  target = event.source.root.find_by_path(widget_id) ### DISCUSS: widget_id or widget_selector?
12
12
 
13
- #::Rails.logger.debug "EventHandler: invoking #{target.name}##{state}"
14
- ### DISCUSS: let target access event?
15
- ### pass additional opts to #invoke?
16
- ### DISCUSS: pass block here?
17
- target.opts[:event] = event
18
-
19
- target.invoke(state)
13
+ target.invoke(state, event)
20
14
  end
21
15
 
22
16
  def to_s; "InvokeEventHandler:#{widget_id}##{state}"; end
@@ -5,19 +5,17 @@ require 'apotomo/rails/view_methods'
5
5
  module Rails
6
6
  module ControllerMethods
7
7
  include WidgetShortcuts
8
+ extend ActiveSupport::Concern
8
9
 
9
- def self.included(base) #:nodoc:
10
- base.class_eval do
11
- extend WidgetShortcuts
12
- extend ClassMethods
13
-
14
- class_inheritable_array :has_widgets_blocks
15
- self.has_widgets_blocks = []
16
-
17
- helper ::Apotomo::Rails::ViewMethods
18
-
19
- after_filter :apotomo_freeze
20
- end
10
+ included do
11
+ extend WidgetShortcuts
12
+
13
+ class_inheritable_array :has_widgets_blocks
14
+ self.has_widgets_blocks = []
15
+
16
+ helper ::Apotomo::Rails::ViewMethods
17
+
18
+ after_filter :apotomo_freeze
21
19
  end
22
20
 
23
21
  module ClassMethods
@@ -33,8 +31,6 @@ require 'apotomo/rails/view_methods'
33
31
  def has_widgets(&block)
34
32
  has_widgets_blocks << block
35
33
  end
36
-
37
- alias_method :uses_widgets, :has_widgets
38
34
  end
39
35
 
40
36
  def bound_use_widgets_blocks
@@ -138,25 +134,6 @@ with(window.parent) { setTimeout(function() { window.eval('#{escaped_script}');
138
134
  </script></body></html>", :content_type => 'text/html'
139
135
  end
140
136
 
141
- def respond_to_event(type, options)
142
- handler = ProcEventHandler.new
143
- handler.proc = options[:with]
144
- ### TODO: pass :from => (event source).
145
-
146
- # attach once, not every request:
147
- apotomo_root.evt_table.add_handler_once(handler, :event_type => type)
148
- end
149
-
150
-
151
-
152
- ### DISCUSS: rename? should say "this controller action wants apotomo's deep linking!"
153
- ### DISCUSS: move to deep_link_methods?
154
- def respond_to_url_change
155
- return if apotomo_root.find_widget('deep_link') # add only once.
156
- apotomo_root << widget("apotomo/deep_link_widget", :setup, 'deep_link')
157
- end
158
-
159
-
160
137
  class ProcHash < Array
161
138
  def id_for_proc(proc)
162
139
  proc.to_s.split('@').last
@@ -7,31 +7,7 @@ module Apotomo
7
7
  def js_generator
8
8
  Apotomo.js_generator
9
9
  end
10
-
11
-
12
- # Generates the JavaScript code to report an event of <tt>type</tt> to Apotomo with AJAX.
13
- # As always per default the event source is the currently rendered widget.
14
- # Internally this method just uses <tt>remote_function</tt> for JS output.
15
- #
16
- # Example:
17
- #
18
- # <%= image_tag "cheese.png", :onMouseover => trigger_event(:mouseAlarm) %>
19
- #
20
- # will trigger the event <tt>:mouseAlarm</tt> when moving the mouse over the cheese image.
21
- def trigger_event(type, options={})
22
- js_generator.xhr(url_for_event(type, options))
23
- end
24
-
25
- # Creates a form tag that triggers an event via AJAX when submitted.
26
- # See StatefulWidget::address_for_event for options.
27
- #
28
- # The values of form elements are available via StatefulWidget#param.
29
- def form_to_event(type, options={}, html_options={}, &block)
30
- return multipart_form_to_event(type, options, html_options, &block) if options.delete(:multipart)
31
-
32
- form_remote_tag({:url => url_for_event(type, options), :html => html_options}, &block)
33
- end
34
-
10
+
35
11
  # Creates a form that submits itself via an iFrame and executes the response
36
12
  # in the parent window. This is needed to upload files via AJAX.
37
13
  #
@@ -53,12 +29,7 @@ module Apotomo
53
29
  # url_for_event(:paginate, :page => 2)
54
30
  # #=> http://apotomo.de/mouse/process_event_request?type=paginate&source=mouse&page=2
55
31
  def url_for_event(type, options={})
56
- @cell.url_for_event(type, options)
57
- end
58
-
59
- ### TODO: test me.
60
- def update_url(fragment)
61
- 'SWFAddress.setValue("' + fragment + '");'
32
+ controller.url_for_event(type, options)
62
33
  end
63
34
 
64
35
  ### TODO: test me.
@@ -93,7 +64,7 @@ module Apotomo
93
64
 
94
65
  # Returns the widget id you passed in a has_widgets block.
95
66
  def widget_id
96
- @cell.name
67
+ controller.name
97
68
  end
98
69
  end
99
70
  end
@@ -1,3 +1,3 @@
1
1
  module Apotomo
2
- VERSION = '1.0.1'
2
+ VERSION = '1.0.2'
3
3
  end
@@ -31,8 +31,6 @@ module Apotomo
31
31
  attr_accessor :opts
32
32
  attr_writer :visible
33
33
 
34
- attr_writer :controller
35
-
36
34
  include TreeNode
37
35
 
38
36
  include Onfire
@@ -43,6 +41,8 @@ module Apotomo
43
41
 
44
42
  helper Apotomo::Rails::ViewHelper
45
43
 
44
+ abstract!
45
+ undef :display # We don't want #display to be listed in #internal_methods.
46
46
 
47
47
  # Runs callbacks for +name+ hook in instance context.
48
48
  def run_widget_hook(name, *args)
@@ -80,8 +80,7 @@ module Apotomo
80
80
 
81
81
  # Returns the rendered content for the widget by running the state method for <tt>state</tt>.
82
82
  # This might lead us to some other state since the state method could call #jump_to_state.
83
- def invoke(state=nil, &block)
84
- @invoke_block = block ### DISCUSS: store block so we don't have to pass it 10 times?
83
+ def invoke(state=nil, event=nil)
85
84
  logger.debug "\ninvoke on #{name} with #{state.inspect}"
86
85
 
87
86
  if state.blank?
@@ -91,7 +90,12 @@ module Apotomo
91
90
  logger.debug "#{name}: transition: #{last_state} to #{state}"
92
91
  logger.debug " ...#{state}"
93
92
 
94
- render_state(state)
93
+ #render_state(state)
94
+
95
+ return process(state, event) if method(state).arity == 1
96
+
97
+ opts[:event] = event
98
+ process(state)
95
99
  end
96
100
 
97
101
 
@@ -236,7 +240,7 @@ module Apotomo
236
240
  def address_for_event(type, options={})
237
241
  options.reverse_merge! :source => name,
238
242
  :type => type,
239
- :controller => parent_controller.controller_name # DISCUSS: dependency to parent_controller.
243
+ :controller => parent_controller.controller_path # DISCUSS: dependency to parent_controller.
240
244
  end
241
245
 
242
246
  def url_for_event(type, options={})
@@ -38,6 +38,7 @@ module Apotomo
38
38
  container(*args)
39
39
  end
40
40
 
41
+ # TODO: deprecate.
41
42
  def cell(base_name, states, id, *args)
42
43
  widget(base_name.to_s + '_cell', states, id, *args)
43
44
  end
@@ -116,7 +116,7 @@ class ControllerMethodsTest < ActionController::TestCase
116
116
 
117
117
  context "invoking #url_for_event" do
118
118
  should "compute an url for any widget" do
119
- assert_equal "/barn/render_event_response?source=mouse&volume=9&type=footsteps", @controller.url_for_event(:footsteps, :source => :mouse, :volume => 9)
119
+ assert_equal "/barn/render_event_response?source=mouse&type=footsteps&volume=9", @controller.url_for_event(:footsteps, :source => :mouse, :volume => 9)
120
120
  end
121
121
  end
122
122
 
@@ -1,74 +1,92 @@
1
1
  require 'test_helper'
2
2
  require 'action_view/test_case'
3
3
 
4
- class ViewHelperTest < ActionView::TestCase
5
- include Apotomo::TestCaseMethods::TestController
4
+ class ViewHelperTest < Apotomo::TestCase
5
+ include ActionDispatch::Assertions::DomAssertions
6
+ include Apotomo::TestCase::TestController
6
7
 
7
- tests Apotomo::Rails::ViewHelper
8
-
9
- context "A widget state view" do
10
- setup do
11
- @cell = mouse_mock('mum')
8
+ # TODO: move to Apotomo::TestCase, refactor, test.
9
+ class MouseWidget < Apotomo::Widget
10
+ end
11
+ def in_view(subject, &block)
12
+ if subject.kind_of?(Apotomo::Widget)
13
+ subject.opts[:block] = block
14
+ else
15
+ subject = subject.new(@controller, 'mum', :display, :block => block)
12
16
  end
17
+
18
+ setup_test_states_in(subject) unless subject.respond_to?(:in_view)# add #in_view state to subject cell.
13
19
 
20
+ subject.class.action_methods << "in_view"
21
+
22
+ subject.invoke(:in_view)
23
+ end
24
+ def mouse_mock(id='mum', start_state=:eat, opts={}, &block)
25
+ mouse = MouseWidget.new(parent_controller, id, start_state, opts)
26
+ mouse.instance_eval &block if block_given?
27
+ mouse
28
+ end
29
+
30
+
31
+ context "A widget state view" do
14
32
  teardown do
15
33
  Apotomo.js_framework = :prototype
16
34
  end
17
35
 
18
-
19
- should "respond to #multipart_form_to_event" do
20
- assert_dom_equal "<iframe id=\"apotomo_iframe\" name=\"apotomo_iframe\" style=\"display: none;\"></iframe><form accept-charset=\"UTF-8\" action=\"/barn/render_event_response?apotomo_iframe=true&amp;source=mum&amp;type=footsteps\" enctype=\"multipart/form-data\" method=\"post\" target=\"apotomo_iframe\"><div style=\"margin:0;padding:0;display:inline\"><input name=\"utf8\" type=\"hidden\" value=\"&#x2713;\" /></div></form>",
21
- multipart_form_to_event(:footsteps)
22
- end
23
-
24
- should "render multipart form if :multipart => true" do
25
- assert_dom_equal "<iframe id=\"apotomo_iframe\" name=\"apotomo_iframe\" style=\"display: none;\"></iframe><form accept-charset=\"UTF-8\" action=\"/barn/render_event_response?apotomo_iframe=true&amp;source=mum&amp;type=footsteps\" enctype=\"multipart/form-data\" method=\"post\" target=\"apotomo_iframe\"><div style=\"margin:0;padding:0;display:inline\"><input name=\"utf8\" type=\"hidden\" value=\"&#x2713;\" /></div></form>",
26
- form_to_event(:footsteps, :multipart => true)
36
+ should_eventually "respond to #multipart_form_to_event" do
37
+ assert_dom_equal( "<iframe id=\"apotomo_iframe\" name=\"apotomo_iframe\" style=\"display: none;\"></iframe><form accept-charset=\"UTF-8\" action=\"/barn/render_event_response?apotomo_iframe=true&amp;source=mum&amp;type=footsteps\" enctype=\"multipart/form-data\" method=\"post\" target=\"apotomo_iframe\"><div style=\"margin:0;padding:0;display:inline\"><input name=\"utf8\" type=\"hidden\" value=\"&#x2713;\" /></div></form>",
38
+ in_view(MouseWidget) do
39
+ multipart_form_to_event(:footsteps)
40
+ end)
27
41
  end
28
42
 
29
- should "respond to #trigger_event" do
30
- assert_dom_equal "new Ajax.Request(\"/barn/render_event_response?source=mum&type=footsteps\")",
31
- trigger_event(:footsteps)
32
- end
33
-
34
- should "render RightJS if set" do
35
- Apotomo.js_framework = :right
36
-
37
- assert_dom_equal "new Xhr(\"/barn/render_event_response?source=mum&type=footsteps\", {evalScripts:true}).send()", trigger_event(:footsteps)
43
+ should "respond to #url_for_event" do
44
+ assert_equal("/barn/render_event_response?source=mum&amp;type=footsteps", in_view(MouseWidget) do
45
+ url_for_event(:footsteps)
46
+ end)
38
47
  end
39
48
 
40
- should "respond to #url_for_event" do
41
- assert_equal("/barn/render_event_response?source=mum&type=footsteps", url_for_event(:footsteps))
49
+ should "respond to #url_for_event with a namespaced controller" do
50
+ @controller = namespaced_controller
51
+ assert_equal("/farm/barn/render_event_response?source=mum&amp;type=footsteps", in_view(MouseWidget) do
52
+ url_for_event(:footsteps)
53
+ end)
42
54
  end
43
55
 
44
56
  should "respond to #widget_div" do
45
- assert_equal '<div id="mum">squeak!</div>', widget_div { "squeak!" }
57
+ assert_equal('<div id="mum">squeak!</div>', in_view(MouseWidget) do widget_div { "squeak!" } end)
46
58
  end
47
59
 
48
60
  should "respond to #widget_div with options" do
49
- assert_equal '<div class="mouse" id="kid">squeak!</div>', widget_div(:id => 'kid', :class => "mouse") { "squeak!" }
61
+ assert_equal('<div class="mouse" id="kid">squeak!</div>', in_view(MouseWidget) do
62
+ widget_div(:id => 'kid', :class => "mouse") { "squeak!" }
63
+ end)
50
64
  end
51
65
 
52
66
  should "respond to #widget_id" do
53
- assert_equal 'mum', widget_id
67
+ assert_equal('mum', in_view(MouseWidget){ widget_id })
54
68
  end
55
69
 
56
70
  context "#widget_javascript" do
57
71
 
58
72
  should "usually render a javascript block" do
59
- assert_equal "<script type=\"text/javascript\">\n//<![CDATA[\nalert(\"Beer!\")\n//]]>\n</script>", widget_javascript { 'alert("Beer!")' }
73
+ assert_equal("<script type=\"text/javascript\">\n//<![CDATA[\nalert(&quot;Beer!&quot;)\n//]]>\n</script>", in_view(MouseWidget) do
74
+ widget_javascript { 'alert("Beer!")' }
75
+ end)
60
76
  end
61
77
 
62
- should "be quiet if suppress_js is set" do
78
+ # FIXME: get the test running?
79
+ should_eventually "be quiet if suppress_js is set" do
63
80
  @suppress_js = true ### TODO: use a local, not an instance variable.
64
- assert_equal nil, widget_javascript { 'alert("Beer!")' }
65
- end
66
-
67
- should_eventually "capture" do
68
- puts "capturing"
69
- v = ActionView::Base.new
70
- c = v.capture do "capture me!" end
71
- puts c.inspect
81
+ mum = mouse_mock do
82
+ def in_view
83
+ render :suppress_js => true
84
+ end
85
+ end
86
+
87
+ assert_equal(nil, in_view(mum) do
88
+ widget_javascript { 'alert("Beer!")' }
89
+ end)
72
90
  end
73
91
  end
74
92
  end
@@ -71,25 +71,28 @@ module Apotomo
71
71
  # Creates a mock controller instance. Currently, each widget needs a parent controller instance due to some
72
72
  # sucky dependency in cells.
73
73
  def barn_controller!
74
- @controller = Class.new(ActionController::Base) do
75
- def initialize
76
- extend ActionController::UrlWriter
77
- self.params = {}
74
+ @controller = Class.new(ApotomoController) do
75
+ def initialize(*)
76
+ super
78
77
  self.request = ActionController::TestRequest.new
79
78
  end
80
79
 
81
80
  def self.name; "BarnController"; end
82
81
 
83
82
  def self.default_url_options; {:controller => :barn}; end
84
- include Apotomo::Rails::ControllerMethods
85
83
  end.new
86
- ### FIXME: @controller.session = {}
87
84
  end
88
85
 
89
86
  def parent_controller
90
87
  @controller
91
88
  end
92
89
 
90
+ def namespaced_controller
91
+ controller = Farm::BarnController.new
92
+ controller.request = ActionController::TestRequest.new
93
+ controller
94
+ end
95
+
93
96
  end
94
97
  end
95
98
  end
data/test/test_helper.rb CHANGED
@@ -29,12 +29,29 @@ end
29
29
 
30
30
  class ApotomoController < ActionController::Base
31
31
  include Apotomo::Rails::ControllerMethods
32
+ include Rails.application.routes.url_helpers
32
33
  end
33
34
 
35
+ module Farm
36
+ class BarnController < ApotomoController
37
+ end
38
+ end
39
+
40
+
34
41
  class MouseCell < Apotomo::StatefulWidget
35
42
  def eating; render; end
43
+ def squeak; render; end
44
+ def educate; render; end
45
+ def snooze; render; end
46
+ def listen; render; end
47
+ def answer_squeak; render; end
48
+ def peek; render; end
49
+ def alert; end
50
+ def escape; end
51
+ def snuggle; end
36
52
  end
37
53
 
54
+ ### TODO: 2brm?
38
55
  class RenderingTestCell < Apotomo::StatefulWidget
39
56
  attr_reader :brain
40
57
  attr_reader :rendered_children
@@ -48,6 +65,6 @@ end
48
65
 
49
66
 
50
67
  # Enable dynamic states so we can do Cell.class_eval { def ... } at runtime.
51
- class Apotomo::Widget
68
+ Apotomo::Widget.class_eval do
52
69
  def action_method?(*); true; end
53
70
  end
@@ -39,6 +39,38 @@ class EventMethodsTest < Test::Unit::TestCase
39
39
  assert_equal ['answer squeak', 'answer squeak'], @mum.list
40
40
  end
41
41
 
42
+ should "also accept an event argument only" do
43
+ @mum.respond_to_event :answer_squeak
44
+ @mum.fire :answer_squeak
45
+ assert_equal ['answer squeak'], @mum.list
46
+ end
47
+
48
+ should "make pass the event into the triggered state" do
49
+ @mum.instance_eval do
50
+ respond_to_event :footsteps
51
+
52
+ def footsteps(evt)
53
+ list << evt.type
54
+ end
55
+ end
56
+
57
+ @mum.trigger :footsteps
58
+ assert_equal ["escape", :footsteps], @mum.list
59
+ end
60
+
61
+ should "accept payload data for the event" do
62
+ @mum.respond_to_event :answer_squeak
63
+ @mum.instance_eval do
64
+ def answer_squeak
65
+ evt = @opts[:event]
66
+ list << evt.data
67
+ end
68
+ end
69
+
70
+ @mum.fire :answer_squeak, :volume => 9
71
+ assert_equal [{:volume => 9}], @mum.list
72
+ end
73
+
42
74
  context "#responds_to_event in class context" do
43
75
  setup do
44
76
  class AdultMouseCell < MouseCell
@@ -58,7 +90,6 @@ class EventMethodsTest < Test::Unit::TestCase
58
90
  end
59
91
  end
60
92
 
61
-
62
93
  context "#trigger" do
63
94
  should "be an alias for #fire" do
64
95
  @kid.trigger :footsteps
@@ -77,7 +108,6 @@ class EventMethodsTest < Test::Unit::TestCase
77
108
  @mum.fire :footsteps
78
109
  assert_equal ["escape"], @mum.page_updates
79
110
  end
80
-
81
111
  end
82
112
 
83
113
  end
@@ -44,8 +44,6 @@ class InvokeTest < Test::Unit::TestCase
44
44
 
45
45
  should "automatically follow the transitions if defined" do
46
46
  assert_equal 'snuggle', @mum.last_state
47
- puts "invoooooooooooooogue"
48
- puts @mum.last_state.inspect
49
47
  @mum.invoke
50
48
  assert_equal 'educate', @mum.last_state
51
49
  end
@@ -75,6 +75,11 @@ class WidgetTest < ActiveSupport::TestCase
75
75
  should "accept arbitrary options" do
76
76
  assert_equal({:volume=>"loud", :source=>"mum", :type=>:squeak, :controller=>"barn"}, @mum.address_for_event(:squeak, :volume => 'loud'))
77
77
  end
78
+
79
+ should "work with controller namespaces" do
80
+ @mum = Apotomo::Widget.new(namespaced_controller, 'mum', :squeak)
81
+ assert_equal({:source=>"mum", :type=>:squeak, :controller=>"farm/barn"}, @mum.address_for_event(:squeak))
82
+ end
78
83
  end
79
84
 
80
85
  context "implementing visibility" do
@@ -132,5 +137,20 @@ class WidgetTest < ActiveSupport::TestCase
132
137
  assert_equal 'shrew', @mum.param(:type)
133
138
  assert_equal 'Logitech', @mum.param(:brand)
134
139
  end
140
+
141
+
142
+ # internal_methods:
143
+ should "not list internal methods in action_methods" do
144
+ assert_equal [], Class.new(Apotomo::Widget).action_methods
145
+ end
146
+
147
+ should "list both local and inherited states in Widget.action_methods" do
148
+ assert MouseCell.action_methods.collect{ |m| m.to_s }.include?("eating")
149
+ assert Class.new(MouseCell).action_methods.collect{ |m| m.to_s }.include?("eating")
150
+ end
151
+
152
+ should "not list #display in internal_methods although it's defined in Object" do
153
+ assert_not Apotomo::Widget.internal_methods.include?(:display)
154
+ end
135
155
  end
136
156
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 0
8
- - 1
9
- version: 1.0.1
8
+ - 2
9
+ version: 1.0.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Nick Sutterer
@@ -14,13 +14,138 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-11-21 00:00:00 +01:00
17
+ date: 2011-01-06 00:00:00 +01:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
- name: cells
21
+ name: rails
22
22
  prerelease: false
23
23
  requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 3
30
+ - 0
31
+ version: "3.0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: cells
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ~>
41
+ - !ruby/object:Gem::Version
42
+ segments:
43
+ - 3
44
+ - 4
45
+ version: "3.4"
46
+ type: :runtime
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: onfire
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ segments:
57
+ - 0
58
+ - 1
59
+ - 1
60
+ version: 0.1.1
61
+ type: :runtime
62
+ version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: hooks
65
+ prerelease: false
66
+ requirement: &id004 !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ~>
70
+ - !ruby/object:Gem::Version
71
+ segments:
72
+ - 0
73
+ - 1
74
+ - 3
75
+ version: 0.1.3
76
+ type: :runtime
77
+ version_requirements: *id004
78
+ - !ruby/object:Gem::Dependency
79
+ name: jeweler
80
+ prerelease: false
81
+ requirement: &id005 !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ type: :runtime
90
+ version_requirements: *id005
91
+ - !ruby/object:Gem::Dependency
92
+ name: shoulda
93
+ prerelease: false
94
+ requirement: &id006 !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ segments:
100
+ - 0
101
+ version: "0"
102
+ type: :runtime
103
+ version_requirements: *id006
104
+ - !ruby/object:Gem::Dependency
105
+ name: mocha
106
+ prerelease: false
107
+ requirement: &id007 !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ segments:
113
+ - 0
114
+ version: "0"
115
+ type: :runtime
116
+ version_requirements: *id007
117
+ - !ruby/object:Gem::Dependency
118
+ name: sqlite3-ruby
119
+ prerelease: false
120
+ requirement: &id008 !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - "="
124
+ - !ruby/object:Gem::Version
125
+ segments:
126
+ - 1
127
+ - 2
128
+ - 5
129
+ version: 1.2.5
130
+ type: :runtime
131
+ version_requirements: *id008
132
+ - !ruby/object:Gem::Dependency
133
+ name: capybara
134
+ prerelease: false
135
+ requirement: &id009 !ruby/object:Gem::Requirement
136
+ none: false
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ segments:
141
+ - 0
142
+ version: "0"
143
+ type: :runtime
144
+ version_requirements: *id009
145
+ - !ruby/object:Gem::Dependency
146
+ name: cells
147
+ prerelease: false
148
+ requirement: &id010 !ruby/object:Gem::Requirement
24
149
  none: false
25
150
  requirements:
26
151
  - - ~>
@@ -31,14 +156,14 @@ dependencies:
31
156
  - 2
32
157
  version: 3.4.2
33
158
  type: :runtime
34
- version_requirements: *id001
159
+ version_requirements: *id010
35
160
  - !ruby/object:Gem::Dependency
36
161
  name: rails
37
162
  prerelease: false
38
- requirement: &id002 !ruby/object:Gem::Requirement
163
+ requirement: &id011 !ruby/object:Gem::Requirement
39
164
  none: false
40
165
  requirements:
41
- - - ">="
166
+ - - ~>
42
167
  - !ruby/object:Gem::Version
43
168
  segments:
44
169
  - 3
@@ -46,11 +171,11 @@ dependencies:
46
171
  - 0
47
172
  version: 3.0.0
48
173
  type: :runtime
49
- version_requirements: *id002
174
+ version_requirements: *id011
50
175
  - !ruby/object:Gem::Dependency
51
176
  name: onfire
52
177
  prerelease: false
53
- requirement: &id003 !ruby/object:Gem::Requirement
178
+ requirement: &id012 !ruby/object:Gem::Requirement
54
179
  none: false
55
180
  requirements:
56
181
  - - ">="
@@ -61,11 +186,11 @@ dependencies:
61
186
  - 0
62
187
  version: 0.1.0
63
188
  type: :runtime
64
- version_requirements: *id003
189
+ version_requirements: *id012
65
190
  - !ruby/object:Gem::Dependency
66
191
  name: hooks
67
192
  prerelease: false
68
- requirement: &id004 !ruby/object:Gem::Requirement
193
+ requirement: &id013 !ruby/object:Gem::Requirement
69
194
  none: false
70
195
  requirements:
71
196
  - - ~>
@@ -76,7 +201,7 @@ dependencies:
76
201
  - 3
77
202
  version: 0.1.3
78
203
  type: :runtime
79
- version_requirements: *id004
204
+ version_requirements: *id013
80
205
  description: Web component framework for Rails providing page widgets that trigger events and know when and how to update themselves with AJAX.
81
206
  email: apotonick@gmail.com
82
207
  executables: []
@@ -87,6 +212,7 @@ extra_rdoc_files:
87
212
  - README.rdoc
88
213
  - TODO
89
214
  files:
215
+ - CHANGES.textile
90
216
  - Gemfile
91
217
  - README.rdoc
92
218
  - Rakefile
@@ -119,78 +245,78 @@ files:
119
245
  - lib/generators/apotomo/templates/widget_test.rb
120
246
  - lib/generators/apotomo/widget_generator.rb
121
247
  - lib/tasks.rake
122
- - test/fixtures/mouse/feed.html.erb
123
- - test/fixtures/mouse/eating.html.erb
124
- - test/fixtures/mouse/make_me_squeak.html.erb
125
- - test/fixtures/mouse/posing.html.erb
126
- - test/fixtures/mouse/educate.html.erb
127
- - test/fixtures/mouse/snuggle.html.erb
128
- - test/fixtures/mouse/content.html.erb
129
- - test/fixtures/application_widget_tree.rb
130
- - test/rails/view_methods_test.rb
131
- - test/rails/controller_methods_test.rb
132
- - test/rails/view_helper_test.rb
133
- - test/rails/widget_generator_test.rb
134
- - test/rails/rails_integration_test.rb
135
- - test/test_helper.rb
136
- - test/support/test_case_methods.rb
248
+ - test/dummy/Rakefile
249
+ - test/dummy/app/controllers/application_controller.rb
250
+ - test/dummy/app/helpers/application_helper.rb
251
+ - test/dummy/app/views/layouts/application.html.erb
252
+ - test/dummy/config.ru
137
253
  - test/dummy/config/application.rb
138
- - test/dummy/config/initializers/session_store.rb
139
- - test/dummy/config/initializers/mime_types.rb
140
- - test/dummy/config/initializers/secret_token.rb
141
- - test/dummy/config/initializers/inflections.rb
142
- - test/dummy/config/initializers/backtrace_silencers.rb
143
- - test/dummy/config/locales/en.yml
144
- - test/dummy/config/routes.rb
145
254
  - test/dummy/config/boot.rb
255
+ - test/dummy/config/database.yml
146
256
  - test/dummy/config/environment.rb
257
+ - test/dummy/config/environments/development.rb
147
258
  - test/dummy/config/environments/production.rb
148
259
  - test/dummy/config/environments/test.rb
149
- - test/dummy/config/environments/development.rb
150
- - test/dummy/config/database.yml
151
- - test/dummy/script/rails
152
- - test/dummy/config.ru
260
+ - test/dummy/config/initializers/backtrace_silencers.rb
261
+ - test/dummy/config/initializers/inflections.rb
262
+ - test/dummy/config/initializers/mime_types.rb
263
+ - test/dummy/config/initializers/secret_token.rb
264
+ - test/dummy/config/initializers/session_store.rb
265
+ - test/dummy/config/locales/en.yml
266
+ - test/dummy/config/routes.rb
153
267
  - test/dummy/db/test.sqlite3
154
- - test/dummy/Rakefile
268
+ - test/dummy/public/404.html
155
269
  - test/dummy/public/422.html
156
- - test/dummy/public/favicon.ico
157
270
  - test/dummy/public/500.html
158
- - test/dummy/public/404.html
159
- - test/dummy/public/javascripts/controls.js
271
+ - test/dummy/public/favicon.ico
160
272
  - test/dummy/public/javascripts/application.js
161
- - test/dummy/public/javascripts/rails.js
273
+ - test/dummy/public/javascripts/controls.js
162
274
  - test/dummy/public/javascripts/dragdrop.js
163
- - test/dummy/public/javascripts/prototype.js
164
275
  - test/dummy/public/javascripts/effects.js
165
- - test/dummy/app/controllers/application_controller.rb
166
- - test/dummy/app/views/layouts/application.html.erb
167
- - test/dummy/app/helpers/application_helper.rb
276
+ - test/dummy/public/javascripts/prototype.js
277
+ - test/dummy/public/javascripts/rails.js
278
+ - test/dummy/script/rails
279
+ - test/fixtures/application_widget_tree.rb
280
+ - test/fixtures/mouse/content.html.erb
281
+ - test/fixtures/mouse/eating.html.erb
282
+ - test/fixtures/mouse/educate.html.erb
283
+ - test/fixtures/mouse/feed.html.erb
284
+ - test/fixtures/mouse/make_me_squeak.html.erb
285
+ - test/fixtures/mouse/posing.html.erb
286
+ - test/fixtures/mouse/snuggle.html.erb
287
+ - test/rails/controller_methods_test.rb
288
+ - test/rails/rails_integration_test.rb
289
+ - test/rails/view_helper_test.rb
290
+ - test/rails/view_methods_test.rb
291
+ - test/rails/widget_generator_test.rb
292
+ - test/support/test_case_methods.rb
293
+ - test/test_helper.rb
294
+ - test/unit/apotomo_test.rb
295
+ - test/unit/container_test.rb
168
296
  - test/unit/event_handler_test.rb
169
- - test/unit/widget_shortcuts_test.rb
170
- - test/unit/stateful_widget_test.rb
171
- - test/unit/test_addressing.rb
297
+ - test/unit/event_methods_test.rb
298
+ - test/unit/event_test.rb
172
299
  - test/unit/invoke_test.rb
173
- - test/unit/container_test.rb
174
- - test/unit/test_tab_panel.rb
175
- - test/unit/test_jump_to_state.rb
176
- - test/unit/render_test.rb
177
- - test/unit/test_case_test.rb
178
- - test/unit/apotomo_test.rb
179
- - test/unit/request_processor_test.rb
180
300
  - test/unit/javascript_generator_test.rb
181
301
  - test/unit/onfire_integration_test.rb
182
302
  - test/unit/persistence_test.rb
303
+ - test/unit/render_test.rb
304
+ - test/unit/request_processor_test.rb
305
+ - test/unit/stateful_widget_test.rb
306
+ - test/unit/test_addressing.rb
307
+ - test/unit/test_case_test.rb
308
+ - test/unit/test_jump_to_state.rb
309
+ - test/unit/test_tab_panel.rb
183
310
  - test/unit/transition_test.rb
184
- - test/unit/event_test.rb
185
- - test/unit/event_methods_test.rb
311
+ - test/unit/widget_shortcuts_test.rb
186
312
  - test/unit/widget_test.rb
187
313
  has_rdoc: true
188
314
  homepage: http://apotomo.de
189
315
  licenses: []
190
316
 
191
317
  post_install_message:
192
- rdoc_options:
193
- - --charset=UTF-8
318
+ rdoc_options: []
319
+
194
320
  require_paths:
195
321
  - lib
196
322
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -217,68 +343,68 @@ signing_key:
217
343
  specification_version: 3
218
344
  summary: Web components for Rails.
219
345
  test_files:
220
- - test/fixtures/mouse/feed.html.erb
221
- - test/fixtures/mouse/eating.html.erb
222
- - test/fixtures/mouse/make_me_squeak.html.erb
223
- - test/fixtures/mouse/posing.html.erb
224
- - test/fixtures/mouse/educate.html.erb
225
- - test/fixtures/mouse/snuggle.html.erb
226
- - test/fixtures/mouse/content.html.erb
227
- - test/fixtures/application_widget_tree.rb
228
- - test/rails/view_methods_test.rb
229
- - test/rails/controller_methods_test.rb
230
- - test/rails/view_helper_test.rb
231
- - test/rails/widget_generator_test.rb
232
- - test/rails/rails_integration_test.rb
233
- - test/test_helper.rb
234
- - test/support/test_case_methods.rb
346
+ - test/dummy/Rakefile
347
+ - test/dummy/app/controllers/application_controller.rb
348
+ - test/dummy/app/helpers/application_helper.rb
349
+ - test/dummy/app/views/layouts/application.html.erb
350
+ - test/dummy/config.ru
235
351
  - test/dummy/config/application.rb
236
- - test/dummy/config/initializers/session_store.rb
237
- - test/dummy/config/initializers/mime_types.rb
238
- - test/dummy/config/initializers/secret_token.rb
239
- - test/dummy/config/initializers/inflections.rb
240
- - test/dummy/config/initializers/backtrace_silencers.rb
241
- - test/dummy/config/locales/en.yml
242
- - test/dummy/config/routes.rb
243
352
  - test/dummy/config/boot.rb
353
+ - test/dummy/config/database.yml
244
354
  - test/dummy/config/environment.rb
355
+ - test/dummy/config/environments/development.rb
245
356
  - test/dummy/config/environments/production.rb
246
357
  - test/dummy/config/environments/test.rb
247
- - test/dummy/config/environments/development.rb
248
- - test/dummy/config/database.yml
249
- - test/dummy/script/rails
250
- - test/dummy/config.ru
358
+ - test/dummy/config/initializers/backtrace_silencers.rb
359
+ - test/dummy/config/initializers/inflections.rb
360
+ - test/dummy/config/initializers/mime_types.rb
361
+ - test/dummy/config/initializers/secret_token.rb
362
+ - test/dummy/config/initializers/session_store.rb
363
+ - test/dummy/config/locales/en.yml
364
+ - test/dummy/config/routes.rb
251
365
  - test/dummy/db/test.sqlite3
252
- - test/dummy/Rakefile
366
+ - test/dummy/public/404.html
253
367
  - test/dummy/public/422.html
254
- - test/dummy/public/favicon.ico
255
368
  - test/dummy/public/500.html
256
- - test/dummy/public/404.html
257
- - test/dummy/public/javascripts/controls.js
369
+ - test/dummy/public/favicon.ico
258
370
  - test/dummy/public/javascripts/application.js
259
- - test/dummy/public/javascripts/rails.js
371
+ - test/dummy/public/javascripts/controls.js
260
372
  - test/dummy/public/javascripts/dragdrop.js
261
- - test/dummy/public/javascripts/prototype.js
262
373
  - test/dummy/public/javascripts/effects.js
263
- - test/dummy/app/controllers/application_controller.rb
264
- - test/dummy/app/views/layouts/application.html.erb
265
- - test/dummy/app/helpers/application_helper.rb
374
+ - test/dummy/public/javascripts/prototype.js
375
+ - test/dummy/public/javascripts/rails.js
376
+ - test/dummy/script/rails
377
+ - test/fixtures/application_widget_tree.rb
378
+ - test/fixtures/mouse/content.html.erb
379
+ - test/fixtures/mouse/eating.html.erb
380
+ - test/fixtures/mouse/educate.html.erb
381
+ - test/fixtures/mouse/feed.html.erb
382
+ - test/fixtures/mouse/make_me_squeak.html.erb
383
+ - test/fixtures/mouse/posing.html.erb
384
+ - test/fixtures/mouse/snuggle.html.erb
385
+ - test/rails/controller_methods_test.rb
386
+ - test/rails/rails_integration_test.rb
387
+ - test/rails/view_helper_test.rb
388
+ - test/rails/view_methods_test.rb
389
+ - test/rails/widget_generator_test.rb
390
+ - test/support/test_case_methods.rb
391
+ - test/test_helper.rb
392
+ - test/unit/apotomo_test.rb
393
+ - test/unit/container_test.rb
266
394
  - test/unit/event_handler_test.rb
267
- - test/unit/widget_shortcuts_test.rb
268
- - test/unit/stateful_widget_test.rb
269
- - test/unit/test_addressing.rb
395
+ - test/unit/event_methods_test.rb
396
+ - test/unit/event_test.rb
270
397
  - test/unit/invoke_test.rb
271
- - test/unit/container_test.rb
272
- - test/unit/test_tab_panel.rb
273
- - test/unit/test_jump_to_state.rb
274
- - test/unit/render_test.rb
275
- - test/unit/test_case_test.rb
276
- - test/unit/apotomo_test.rb
277
- - test/unit/request_processor_test.rb
278
398
  - test/unit/javascript_generator_test.rb
279
399
  - test/unit/onfire_integration_test.rb
280
400
  - test/unit/persistence_test.rb
401
+ - test/unit/render_test.rb
402
+ - test/unit/request_processor_test.rb
403
+ - test/unit/stateful_widget_test.rb
404
+ - test/unit/test_addressing.rb
405
+ - test/unit/test_case_test.rb
406
+ - test/unit/test_jump_to_state.rb
407
+ - test/unit/test_tab_panel.rb
281
408
  - test/unit/transition_test.rb
282
- - test/unit/event_test.rb
283
- - test/unit/event_methods_test.rb
409
+ - test/unit/widget_shortcuts_test.rb
284
410
  - test/unit/widget_test.rb