apotomo 1.0.0.beta2 → 1.0.0
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/Gemfile +2 -1
- data/README.rdoc +30 -12
- data/Rakefile +2 -2
- data/config/routes.rb +1 -1
- data/lib/apotomo/rails/view_helper.rb +1 -2
- data/lib/apotomo/request_processor.rb +1 -12
- data/lib/apotomo/stateful_widget.rb +22 -1
- data/lib/apotomo/test_case.rb +105 -0
- data/lib/apotomo/version.rb +1 -3
- data/lib/apotomo/widget.rb +10 -55
- data/lib/apotomo.rb +16 -2
- data/lib/generators/apotomo/templates/widget_test.rb +6 -5
- data/lib/tasks.rake +6 -0
- data/test/rails/widget_generator_test.rb +1 -0
- data/test/test_helper.rb +4 -17
- data/test/unit/request_processor_test.rb +0 -4
- data/test/unit/test_case_test.rb +95 -0
- data/test/unit/widget_test.rb +3 -9
- metadata +105 -110
- data/lib/apotomo/caching.rb +0 -37
- data/lib/apotomo/deep_link_methods.rb +0 -90
- data/test/unit/test_caching.rb +0 -53
- data/test/unit/test_widget_shortcuts.rb +0 -44
data/Gemfile
CHANGED
@@ -3,7 +3,7 @@ source "http://rubygems.org"
|
|
3
3
|
gem "rails", "~> 3.0.0"
|
4
4
|
gem "cells", "~> 3.4"
|
5
5
|
gem "onfire"
|
6
|
-
gem "hooks", "~> 0.1.
|
6
|
+
gem "hooks", "~> 0.1.3"
|
7
7
|
|
8
8
|
|
9
9
|
gem "jeweler"
|
@@ -12,3 +12,4 @@ gem "jeweler"
|
|
12
12
|
gem "shoulda"
|
13
13
|
gem "mocha"
|
14
14
|
gem 'sqlite3-ruby', '1.2.5', :require => 'sqlite3' # needed in router_test, whatever.
|
15
|
+
gem "capybara"
|
data/README.rdoc
CHANGED
@@ -22,7 +22,7 @@ Easy as hell.
|
|
22
22
|
|
23
23
|
=== Rails 3
|
24
24
|
|
25
|
-
gem install apotomo
|
25
|
+
gem install apotomo --pre
|
26
26
|
|
27
27
|
=== Rails 2.3
|
28
28
|
|
@@ -42,12 +42,12 @@ Let's wrap that comments block in a widget.
|
|
42
42
|
|
43
43
|
Go and generate a widget stub.
|
44
44
|
|
45
|
-
$ rails generate apotomo:widget CommentsWidget display
|
45
|
+
$ rails generate apotomo:widget CommentsWidget display write --haml
|
46
46
|
create app/cells/
|
47
47
|
create app/cells/comments_widget
|
48
48
|
create app/cells/comments_widget.rb
|
49
49
|
create app/cells/comments_widget/display.html.haml
|
50
|
-
create app/cells/comments_widget/
|
50
|
+
create app/cells/comments_widget/write.html.haml
|
51
51
|
create test/widgets/comments_widget_test.rb
|
52
52
|
|
53
53
|
Nothing special.
|
@@ -60,10 +60,10 @@ You now tell your controller about the new widget.
|
|
60
60
|
include Apotomo::Rails::ControllerMethods
|
61
61
|
|
62
62
|
has_widgets do |root|
|
63
|
-
root << widget('comments_widget', 'post-comments', :
|
63
|
+
root << widget('comments_widget', 'post-comments', :post => @post)
|
64
64
|
end
|
65
65
|
|
66
|
-
The widget is named <tt>post-comments</tt
|
66
|
+
The widget is named <tt>post-comments</tt>. We pass the current post into the widget - the block is executed in controller instance context, that's were <tt>@post</tt> comes from. Handy, isn't it?
|
67
67
|
|
68
68
|
== Render the widget
|
69
69
|
|
@@ -82,18 +82,18 @@ Rendering usually happens in your controller view, <tt>views/posts/show.haml</tt
|
|
82
82
|
A widget is like a cell which is like a mini-controller.
|
83
83
|
|
84
84
|
class CommentsWidget < Apotomo::Widget
|
85
|
-
responds_to_event :submit, :with => :
|
85
|
+
responds_to_event :submit, :with => :write
|
86
86
|
|
87
87
|
def display
|
88
88
|
@comments = param(:post).comments # the parameter from outside.
|
89
89
|
render
|
90
90
|
end
|
91
91
|
|
92
|
-
|
92
|
+
Having +display+ as the default state when rendering, this method collects comments to show and renders its view.
|
93
93
|
|
94
|
-
And look at line 2 - if encountering a <tt>:submit</tt> event we invoke +
|
94
|
+
And look at line 2 - if encountering a <tt>:submit</tt> event we invoke +write+, which is simply another state. How cool is that?
|
95
95
|
|
96
|
-
def
|
96
|
+
def write
|
97
97
|
@comment = Comment.new(:post => param(:post))
|
98
98
|
@comment.update_attributes param(:comment) # like params[].
|
99
99
|
|
@@ -160,7 +160,7 @@ Look, +replace+ basically generates
|
|
160
160
|
|
161
161
|
If that's not what you want, do
|
162
162
|
|
163
|
-
def
|
163
|
+
def write
|
164
164
|
if param(:comment)[:text].explicit?
|
165
165
|
render :text => 'alert("Hey, you wanted to submit a pervert comment!");'
|
166
166
|
end
|
@@ -168,6 +168,25 @@ If that's not what you want, do
|
|
168
168
|
|
169
169
|
Apotomo doesn't depend on _any_ JS framework - you choose!
|
170
170
|
|
171
|
+
== Testing
|
172
|
+
|
173
|
+
Apotomo comes with its own test case and assertions to <b>build rock-solid web components</b>.
|
174
|
+
|
175
|
+
class CommentsWidgetTest < Apotomo::TestCase
|
176
|
+
has_widgets do |root|
|
177
|
+
root << widget(:comments_widget, 'me', :post => @pervert_post)
|
178
|
+
end
|
179
|
+
|
180
|
+
def test_render
|
181
|
+
render_widget 'me'
|
182
|
+
assert_select "li#me"
|
183
|
+
|
184
|
+
trigger :submit, :comment => {:text => "Sex on the beach"}
|
185
|
+
assert_response 'alert("Hey, you wanted to submit a pervert comment!");'
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
You can render your widgets, spec the markup, trigger events and assert the event responses, so far. If you need more, let us know!
|
171
190
|
|
172
191
|
== More features
|
173
192
|
|
@@ -175,8 +194,7 @@ There's even more, too much for a simple README.
|
|
175
194
|
|
176
195
|
[Statefulness] Deriving your widget from +StatefulWidget+ gives you free statefulness.
|
177
196
|
[Composability] Widgets can range from small standalone components to nested widget trees like complex dashboards.
|
178
|
-
[Bubbling events] Events bubble up from their triggering source to root and thus can be observed, providing a way to implement loosely coupled, distributable components.
|
179
|
-
[Testing] Apotomo comes with testing assertions to build rock-solid web components.
|
197
|
+
[Bubbling events] Events bubble up from their triggering source to root and thus can be observed, providing a way to implement loosely coupled, distributable components.
|
180
198
|
[Team-friendly] Widgets encourage encapsulation and help having different developers working on different components without getting out of bounds.
|
181
199
|
|
182
200
|
|
data/Rakefile
CHANGED
@@ -25,7 +25,7 @@ Jeweler::Tasks.new do |spec|
|
|
25
25
|
spec.name = "apotomo"
|
26
26
|
spec.version = ::Apotomo::VERSION
|
27
27
|
spec.summary = %{Web components for Rails.}
|
28
|
-
spec.description = "Web
|
28
|
+
spec.description = "Web component framework for Rails providing page widgets that trigger events and know when and how to update themselves with AJAX."
|
29
29
|
spec.homepage = "http://apotomo.de"
|
30
30
|
spec.authors = ["Nick Sutterer"]
|
31
31
|
spec.email = "apotonick@gmail.com"
|
@@ -36,7 +36,7 @@ Jeweler::Tasks.new do |spec|
|
|
36
36
|
spec.add_dependency 'cells', '~> 3.4.2'
|
37
37
|
spec.add_dependency 'rails', '>= 3.0.0'
|
38
38
|
spec.add_dependency 'onfire', '>= 0.1.0'
|
39
|
-
spec.add_dependency 'hooks', '~> 0.1.
|
39
|
+
spec.add_dependency 'hooks', '~> 0.1.3'
|
40
40
|
end
|
41
41
|
|
42
42
|
Jeweler::GemcutterTasks.new
|
data/config/routes.rb
CHANGED
@@ -53,8 +53,7 @@ module Apotomo
|
|
53
53
|
# url_for_event(:paginate, :page => 2)
|
54
54
|
# #=> http://apotomo.de/mouse/process_event_request?type=paginate&source=mouse&page=2
|
55
55
|
def url_for_event(type, options={})
|
56
|
-
|
57
|
-
@cell.url_for_event(type, options) # FIXME: don't access @parent_controller but @cell.
|
56
|
+
@cell.url_for_event(type, options)
|
58
57
|
end
|
59
58
|
|
60
59
|
### TODO: test me.
|
@@ -17,8 +17,6 @@ module Apotomo
|
|
17
17
|
|
18
18
|
flushed_root ### FIXME: set internal mode to flushed
|
19
19
|
end
|
20
|
-
|
21
|
-
#handle_version!(options[:version])
|
22
20
|
end
|
23
21
|
|
24
22
|
def attach_stateless_blocks_for(blocks, root, controller)
|
@@ -30,16 +28,7 @@ module Apotomo
|
|
30
28
|
@widgets_flushed = true
|
31
29
|
#widget('apotomo/widget', 'root')
|
32
30
|
end
|
33
|
-
|
34
|
-
### DISCUSS: do we need the version feature, or should we push that into user code?
|
35
|
-
def handle_version!(version)
|
36
|
-
return if version.blank?
|
37
|
-
return if root.version == version
|
38
|
-
|
39
|
-
@root = flushed_root
|
40
|
-
@root.version = version
|
41
|
-
end
|
42
|
-
|
31
|
+
|
43
32
|
def widgets_flushed?; @widgets_flushed; end
|
44
33
|
|
45
34
|
# Fires the request event in the widget tree and collects the rendered page updates.
|
@@ -4,5 +4,26 @@ require 'apotomo/persistence'
|
|
4
4
|
module Apotomo
|
5
5
|
class StatefulWidget < Widget
|
6
6
|
include Persistence
|
7
|
+
|
8
|
+
attr_accessor :version
|
9
|
+
|
10
|
+
def initialize(*)
|
11
|
+
super
|
12
|
+
@version = 0
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
# Defines the instance vars that should <em>not</em> survive between requests,
|
17
|
+
# which means they're not frozen in Apotomo::StatefulWidget#freeze.
|
18
|
+
def ivars_to_forget
|
19
|
+
unfreezable_ivars
|
20
|
+
end
|
21
|
+
|
22
|
+
def unfreezable_ivars
|
23
|
+
[:@childrenHash, :@children, :@parent, :@parent_controller, :@_request, :@_config, :@cell, :@invoke_block, :@rendered_children, :@page_updates, :@opts, :@params,
|
24
|
+
:@suppress_javascript ### FIXME: implement with ActiveHelper and :locals.
|
25
|
+
|
26
|
+
]
|
27
|
+
end
|
7
28
|
end
|
8
|
-
end
|
29
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'cell/test_case'
|
2
|
+
|
3
|
+
module Apotomo
|
4
|
+
# Testing is fun. Test your widgets!
|
5
|
+
#
|
6
|
+
# This class helps you testing widgets where it can. It is similar as in a controller.
|
7
|
+
# A declarative test would look like
|
8
|
+
#
|
9
|
+
# class BlogWidgetTest < Apotomo::TestCase
|
10
|
+
# has_widgets do |root|
|
11
|
+
# root << widget(:comments_widget, 'post-comments')
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# it "should be rendered nicely" do
|
15
|
+
# render_widget 'post-comments'
|
16
|
+
#
|
17
|
+
# assert_select "div#post-comments", "Comments for this post"
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# it "should redraw on :update" do
|
21
|
+
# trigger :update
|
22
|
+
# assert_response "$(\"post-comments\").update ..."
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# For unit testing, you can grab an instance of your tested widget.
|
26
|
+
#
|
27
|
+
# it "should be visible" do
|
28
|
+
# assert root['post-comments'].visible?
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# See also in Cell::TestCase.
|
32
|
+
class TestCase < Cell::TestCase
|
33
|
+
class << self
|
34
|
+
def has_widgets_blocks; @has_widgets; end
|
35
|
+
|
36
|
+
# Setup a widget tree as you're used to it from your controller. Executed in test context.
|
37
|
+
def has_widgets(&block)
|
38
|
+
@has_widgets = block # DISCUSS: use ControllerMethods?
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def setup
|
43
|
+
super
|
44
|
+
@controller.instance_eval do
|
45
|
+
def controller_name
|
46
|
+
'barn'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
@controller.extend Apotomo::Rails::ControllerMethods
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
# Returns the widget tree from TestCase.has_widgets.
|
54
|
+
def root
|
55
|
+
blk = self.class.has_widgets_blocks or raise "Please setup a widget tree using TestCase.has_widgets"
|
56
|
+
@root ||= widget("apotomo/widget", "root").tap do |root|
|
57
|
+
self.instance_exec(root, &blk)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def parent_controller
|
62
|
+
@controller
|
63
|
+
end
|
64
|
+
|
65
|
+
# Renders the widget +name+.
|
66
|
+
def render_widget(name, options={})
|
67
|
+
@last_invoke = root.find_widget(name).tap { |w| w.opts = options }.invoke # DISCUSS: use ControllerMethods?
|
68
|
+
end
|
69
|
+
|
70
|
+
# Triggers an event of +type+. You have to pass <tt>:source</tt> as options.
|
71
|
+
#
|
72
|
+
# Example:
|
73
|
+
#
|
74
|
+
# trigger :submit, :source => "post-comments"
|
75
|
+
def trigger(type, options)
|
76
|
+
source = root.find_widget(options.delete(:source))
|
77
|
+
source.instance_variable_set :@params, options # TODO: this is just a try-out (what about children?).
|
78
|
+
source.fire(type)
|
79
|
+
root.page_updates # DISCUSS: use ControllerMethods?
|
80
|
+
end
|
81
|
+
|
82
|
+
# After a #trigger this assertion compares the actually triggered page updates with the passed.
|
83
|
+
#
|
84
|
+
# Example:
|
85
|
+
#
|
86
|
+
# trigger :submit, :source => "post-comments"
|
87
|
+
# assert_response "alert(\":submit clicked!\")", /\$\("post-comments"\).update/
|
88
|
+
def assert_response(*content)
|
89
|
+
updates = root.page_updates
|
90
|
+
|
91
|
+
i = 0
|
92
|
+
content.each do |assertion|
|
93
|
+
if assertion.kind_of? Regexp
|
94
|
+
assert_match assertion, updates[i]
|
95
|
+
else
|
96
|
+
assert_equal assertion, updates[i]
|
97
|
+
end
|
98
|
+
|
99
|
+
i+=1
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
include Apotomo::WidgetShortcuts
|
104
|
+
end
|
105
|
+
end
|
data/lib/apotomo/version.rb
CHANGED
data/lib/apotomo/widget.rb
CHANGED
@@ -6,7 +6,6 @@ require 'apotomo/tree_node'
|
|
6
6
|
require 'apotomo/event'
|
7
7
|
require 'apotomo/event_methods'
|
8
8
|
require 'apotomo/transition'
|
9
|
-
require 'apotomo/caching'
|
10
9
|
require 'apotomo/widget_shortcuts'
|
11
10
|
require 'apotomo/rails/view_helper'
|
12
11
|
|
@@ -31,9 +30,8 @@ module Apotomo
|
|
31
30
|
|
32
31
|
attr_accessor :opts
|
33
32
|
attr_writer :visible
|
34
|
-
|
33
|
+
|
35
34
|
attr_writer :controller
|
36
|
-
attr_accessor :version
|
37
35
|
|
38
36
|
include TreeNode
|
39
37
|
|
@@ -41,7 +39,6 @@ module Apotomo
|
|
41
39
|
include EventMethods
|
42
40
|
|
43
41
|
include Transition
|
44
|
-
include Caching
|
45
42
|
include WidgetShortcuts
|
46
43
|
|
47
44
|
helper Apotomo::Rails::ViewHelper
|
@@ -66,13 +63,11 @@ module Apotomo
|
|
66
63
|
@start_state = start_state
|
67
64
|
|
68
65
|
@visible = true
|
69
|
-
@version = 0 ### DISCUSS: neeed in stateLESS?
|
70
|
-
|
71
66
|
@cell = self ### DISCUSS: needed?
|
72
67
|
|
73
68
|
@params = parent_controller.params.dup.merge(opts)
|
74
69
|
|
75
|
-
run_hook
|
70
|
+
run_hook :after_initialize, self
|
76
71
|
end
|
77
72
|
|
78
73
|
def last_state
|
@@ -82,29 +77,6 @@ module Apotomo
|
|
82
77
|
def visible?
|
83
78
|
@visible
|
84
79
|
end
|
85
|
-
|
86
|
-
# Defines the instance vars that should <em>not</em> survive between requests,
|
87
|
-
# which means they're not frozen in Apotomo::StatefulWidget#freeze.
|
88
|
-
def ivars_to_forget
|
89
|
-
unfreezable_ivars
|
90
|
-
end
|
91
|
-
|
92
|
-
def unfreezable_ivars
|
93
|
-
[:@childrenHash, :@children, :@parent, :@parent_controller, :@_request, :@_config, :@cell, :@invoke_block, :@rendered_children, :@page_updates, :@opts, :@params,
|
94
|
-
:@suppress_javascript ### FIXME: implement with ActiveHelper and :locals.
|
95
|
-
|
96
|
-
]
|
97
|
-
end
|
98
|
-
|
99
|
-
# Defines the instance vars which should <em>not</em> be copied to the view.
|
100
|
-
# Called in Cell::Base.
|
101
|
-
def ivars_to_ignore
|
102
|
-
[]
|
103
|
-
end
|
104
|
-
|
105
|
-
### FIXME:
|
106
|
-
def logger; self; end
|
107
|
-
def debug(*args); puts args; end
|
108
80
|
|
109
81
|
# Returns the rendered content for the widget by running the state method for <tt>state</tt>.
|
110
82
|
# This might lead us to some other state since the state method could call #jump_to_state.
|
@@ -256,36 +228,19 @@ module Apotomo
|
|
256
228
|
end
|
257
229
|
|
258
230
|
|
259
|
-
# Returns the address hash to the event controller and the targeted widget.
|
260
|
-
#
|
261
|
-
# Reserved options for <tt>way</tt>:
|
262
|
-
# :source explicitly specifies an event source.
|
263
|
-
# The default is to take the current widget as source.
|
264
|
-
# :type specifies the event type.
|
265
|
-
#
|
266
|
-
# Any other option will be directly passed into the address hash and is
|
267
|
-
# available via StatefulWidget#param in the widget.
|
268
|
-
#
|
269
|
-
# Can be passed to #url_for.
|
270
|
-
#
|
271
|
-
# Example:
|
272
|
-
# address_for_event :type => :squeak, :volume => 9
|
273
|
-
# will result in an address that triggers a <tt>:click</tt> event from the current
|
274
|
-
# widget and also provides the parameter <tt>:item_id</tt>.
|
275
|
-
def address_for_event(options)
|
276
|
-
raise "please specify the event :type" unless options[:type]
|
277
|
-
|
278
|
-
options[:source] ||= self.name
|
279
|
-
options
|
280
|
-
end
|
281
|
-
|
282
231
|
# Returns the widget named <tt>widget_id</tt> as long as it is below self or self itself.
|
283
232
|
def find_widget(widget_id)
|
284
233
|
find {|node| node.name.to_s == widget_id.to_s}
|
285
234
|
end
|
286
235
|
|
287
|
-
def
|
288
|
-
|
236
|
+
def address_for_event(type, options={})
|
237
|
+
options.reverse_merge! :source => name,
|
238
|
+
:type => type,
|
239
|
+
:controller => parent_controller.controller_name # DISCUSS: dependency to parent_controller.
|
240
|
+
end
|
241
|
+
|
242
|
+
def url_for_event(type, options={})
|
243
|
+
apotomo_event_path address_for_event(type, options)
|
289
244
|
end
|
290
245
|
|
291
246
|
alias_method :widget_id, :name
|
data/lib/apotomo.rb
CHANGED
@@ -20,6 +20,9 @@
|
|
20
20
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
21
|
# THE SOFTWARE.
|
22
22
|
|
23
|
+
require "rails/railtie"
|
24
|
+
require 'rails/engine'
|
25
|
+
|
23
26
|
module Apotomo
|
24
27
|
class << self
|
25
28
|
def js_framework=(js_framework)
|
@@ -43,13 +46,24 @@ module Apotomo
|
|
43
46
|
|
44
47
|
class Engine < Rails::Engine
|
45
48
|
end
|
49
|
+
|
50
|
+
class Railtie < Rails::Railtie
|
51
|
+
rake_tasks do
|
52
|
+
load "tasks.rake"
|
53
|
+
end
|
54
|
+
end
|
46
55
|
end
|
47
56
|
|
48
|
-
require 'apotomo/javascript_generator'
|
49
|
-
Apotomo.js_framework = :jquery ### DISCUSS: move to rails.rb
|
50
57
|
|
51
58
|
require 'apotomo/widget'
|
52
59
|
require 'apotomo/stateful_widget'
|
53
60
|
require 'apotomo/container_widget'
|
54
61
|
require 'apotomo/widget_shortcuts'
|
55
62
|
require 'apotomo/rails/controller_methods'
|
63
|
+
|
64
|
+
|
65
|
+
require 'apotomo/javascript_generator'
|
66
|
+
Apotomo.js_framework = :jquery ### DISCUSS: move to rails.rb
|
67
|
+
|
68
|
+
### FIXME: only load in test env.
|
69
|
+
require 'apotomo/test_case' #if defined?("Rails") and Rails.env == "test"
|
@@ -1,11 +1,12 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class <%= class_name %>Test < Apotomo::TestCase
|
4
|
-
|
5
|
-
|
6
|
-
invoke :<%= state %>
|
7
|
-
assert_select "p"
|
4
|
+
has_widgets do |root|
|
5
|
+
root << widget(:<%= file_name %>, 'me')
|
8
6
|
end
|
9
7
|
|
10
|
-
|
8
|
+
test "display" do
|
9
|
+
render_widget 'me'
|
10
|
+
assert_select "h1"
|
11
|
+
end
|
11
12
|
end
|
data/lib/tasks.rake
ADDED
@@ -20,6 +20,7 @@ class WidgetGeneratorTest < Rails::Generators::TestCase
|
|
20
20
|
assert_file "app/cells/mouse_widget/squeak.html.erb", %r(app/cells/mouse_widget/squeak\.html\.erb)
|
21
21
|
|
22
22
|
assert_file "test/widgets/mouse_widget_test.rb", %r(class MouseWidgetTest < Apotomo::TestCase)
|
23
|
+
assert_file "test/widgets/mouse_widget_test.rb", %r(widget\(:mouse_widget, 'me'\))
|
23
24
|
end
|
24
25
|
|
25
26
|
should "create haml assets with --haml" do
|
data/test/test_helper.rb
CHANGED
@@ -3,24 +3,16 @@ require 'rubygems'
|
|
3
3
|
require 'bundler'
|
4
4
|
Bundler.setup
|
5
5
|
|
6
|
-
#require 'rubygems'
|
7
6
|
require 'shoulda'
|
8
|
-
require 'mocha'
|
9
|
-
require 'mocha/integration'
|
10
|
-
|
11
|
-
|
12
7
|
require 'cells'
|
13
|
-
Cell::Base.append_view_path File.expand_path(File.dirname(__FILE__) + "/fixtures")
|
14
|
-
|
15
|
-
require 'rails/engine'
|
16
|
-
|
17
8
|
require 'apotomo'
|
18
|
-
require 'apotomo/widget_shortcuts'
|
19
|
-
require 'apotomo/rails/controller_methods'
|
20
|
-
require 'apotomo/rails/view_methods'
|
21
9
|
|
10
|
+
ENV['RAILS_ENV'] = 'test'
|
11
|
+
require "dummy/config/environment"
|
12
|
+
require "rails/test_help" # sets up ActionController::TestCase's @routes
|
22
13
|
|
23
14
|
|
15
|
+
Cell::Base.append_view_path File.expand_path(File.dirname(__FILE__) + "/fixtures")
|
24
16
|
|
25
17
|
# Load test support files.
|
26
18
|
require File.join(File.dirname(__FILE__), "support/test_case_methods")
|
@@ -59,8 +51,3 @@ end
|
|
59
51
|
class Apotomo::Widget
|
60
52
|
def action_method?(*); true; end
|
61
53
|
end
|
62
|
-
|
63
|
-
ENV['RAILS_ENV'] = 'test'
|
64
|
-
require "dummy/config/environment"
|
65
|
-
#require File.join(File.dirname(__FILE__), '..', 'config/routes.rb') ### TODO: let rails engine handle that.
|
66
|
-
require "rails/test_help" # sets up ActionController::TestCase's @routes
|
@@ -59,10 +59,6 @@ class RequestProcessorTest < ActiveSupport::TestCase
|
|
59
59
|
should "provide a single root-node for #root" do
|
60
60
|
assert_equal 1, @processor.root.size
|
61
61
|
end
|
62
|
-
|
63
|
-
should "initialize version to 0" do
|
64
|
-
assert_equal 0, @processor.root.version
|
65
|
-
end
|
66
62
|
end
|
67
63
|
|
68
64
|
context "with controller" do
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'apotomo/test_case'
|
3
|
+
|
4
|
+
class TestCaseTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
class CommentsWidgetTest < Apotomo::TestCase
|
7
|
+
end
|
8
|
+
|
9
|
+
class CommentsWidget < Apotomo::Widget
|
10
|
+
end
|
11
|
+
|
12
|
+
context "TestCase" do
|
13
|
+
|
14
|
+
context "responding to #root" do
|
15
|
+
class MouseWidgetTest < Apotomo::TestCase
|
16
|
+
end
|
17
|
+
|
18
|
+
setup do
|
19
|
+
@klass = MouseWidgetTest
|
20
|
+
@test = @klass.new(:widget).tap{ |t| t.setup }
|
21
|
+
@klass.has_widgets { |r| r << widget("mouse_cell", 'mum', :eating) }
|
22
|
+
end
|
23
|
+
|
24
|
+
should "respond to #root" do
|
25
|
+
assert_equal ['root', 'mum'], @test.root.collect { |w| w.name }
|
26
|
+
end
|
27
|
+
|
28
|
+
should "raise an error if no has_widgets block given" do
|
29
|
+
exc = assert_raises RuntimeError do
|
30
|
+
@test = Class.new(Apotomo::TestCase).new(:widget).tap{ |t| t.setup }
|
31
|
+
@test.root
|
32
|
+
end
|
33
|
+
|
34
|
+
assert_equal "Please setup a widget tree using TestCase.has_widgets", exc.message
|
35
|
+
end
|
36
|
+
|
37
|
+
should "memorize root" do
|
38
|
+
@test.root.visible=false
|
39
|
+
assert_equal false, @test.root.visible?
|
40
|
+
end
|
41
|
+
|
42
|
+
should "respond to #render_widget" do
|
43
|
+
assert_equal "<div id=\"mum\">burp!</div>", @test.render_widget('mum')
|
44
|
+
assert_equal "<div id=\"mum\">burp!</div>", @test.last_invoke
|
45
|
+
end
|
46
|
+
|
47
|
+
should "respond to #assert_select" do
|
48
|
+
@test.render_widget('mum')
|
49
|
+
|
50
|
+
assert_nothing_raised { @test.assert_select("div#mum", "burp!") }
|
51
|
+
|
52
|
+
exc = assert_raises( MiniTest::Assertion){ @test.assert_select("div#mummy", "burp!"); }
|
53
|
+
assert_equal 'Expected at least 1 element matching "div#mummy", found 0.', exc.message
|
54
|
+
end
|
55
|
+
|
56
|
+
context "using events" do
|
57
|
+
setup do
|
58
|
+
@mum = @test.root['mum']
|
59
|
+
@mum.respond_to_event :footsteps, :with => :squeak
|
60
|
+
@mum.instance_eval do
|
61
|
+
def squeak; render :text => "squeak!"; end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
should "respond to #trigger" do
|
66
|
+
assert_equal ["squeak!"], @test.trigger(:footsteps, :source => 'mum')
|
67
|
+
end
|
68
|
+
|
69
|
+
should "provide options from #trigger to the widget" do
|
70
|
+
@test.trigger(:footsteps, :source => 'mum', :direction => :kitchen)
|
71
|
+
assert_equal :kitchen, @mum.param(:direction)
|
72
|
+
end
|
73
|
+
|
74
|
+
should "respond to #assert_response" do
|
75
|
+
@test.trigger(:footsteps, :source => 'mum')
|
76
|
+
assert @test.assert_response("squeak!")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "responding to parent_controller" do
|
82
|
+
setup do
|
83
|
+
@test = Apotomo::TestCase.new(:widget).tap{ |t| t.setup }
|
84
|
+
end
|
85
|
+
|
86
|
+
should "provide a test controller" do
|
87
|
+
assert_kind_of ActionController::Base, @test.parent_controller
|
88
|
+
end
|
89
|
+
|
90
|
+
should "respond to #controller_name" do
|
91
|
+
assert_equal "barn", @test.parent_controller.controller_name
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
data/test/unit/widget_test.rb
CHANGED
@@ -65,21 +65,15 @@ class WidgetTest < ActiveSupport::TestCase
|
|
65
65
|
|
66
66
|
context "responding to #address_for_event" do
|
67
67
|
should "accept an event :type" do
|
68
|
-
assert_equal({:
|
68
|
+
assert_equal({:source=>"mum", :type=>:squeak, :controller=>"barn"}, @mum.address_for_event(:squeak))
|
69
69
|
end
|
70
70
|
|
71
71
|
should "accept a :source" do
|
72
|
-
assert_equal({:
|
72
|
+
assert_equal({:source=>"kid", :type=>:squeak, :controller=>"barn"}, @mum.address_for_event(:squeak, :source => 'kid'))
|
73
73
|
end
|
74
74
|
|
75
75
|
should "accept arbitrary options" do
|
76
|
-
assert_equal({:
|
77
|
-
end
|
78
|
-
|
79
|
-
should "complain if no type given" do
|
80
|
-
assert_raises RuntimeError do
|
81
|
-
@mum.address_for_event(:source => 'mum')
|
82
|
-
end
|
76
|
+
assert_equal({:volume=>"loud", :source=>"mum", :type=>:squeak, :controller=>"barn"}, @mum.address_for_event(:squeak, :volume => 'loud'))
|
83
77
|
end
|
84
78
|
end
|
85
79
|
|
metadata
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apotomo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
4
|
+
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 1
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
|
10
|
-
version: 1.0.0.beta2
|
9
|
+
version: 1.0.0
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- Nick Sutterer
|
@@ -15,7 +14,7 @@ autorequire:
|
|
15
14
|
bindir: bin
|
16
15
|
cert_chain: []
|
17
16
|
|
18
|
-
date: 2010-
|
17
|
+
date: 2010-11-17 00:00:00 +01:00
|
19
18
|
default_executable:
|
20
19
|
dependencies:
|
21
20
|
- !ruby/object:Gem::Dependency
|
@@ -74,11 +73,11 @@ dependencies:
|
|
74
73
|
segments:
|
75
74
|
- 0
|
76
75
|
- 1
|
77
|
-
-
|
78
|
-
version: 0.1.
|
76
|
+
- 3
|
77
|
+
version: 0.1.3
|
79
78
|
type: :runtime
|
80
79
|
version_requirements: *id004
|
81
|
-
description: Web
|
80
|
+
description: Web component framework for Rails providing page widgets that trigger events and know when and how to update themselves with AJAX.
|
82
81
|
email: apotonick@gmail.com
|
83
82
|
executables: []
|
84
83
|
|
@@ -94,9 +93,7 @@ files:
|
|
94
93
|
- TODO
|
95
94
|
- config/routes.rb
|
96
95
|
- lib/apotomo.rb
|
97
|
-
- lib/apotomo/caching.rb
|
98
96
|
- lib/apotomo/container_widget.rb
|
99
|
-
- lib/apotomo/deep_link_methods.rb
|
100
97
|
- lib/apotomo/event.rb
|
101
98
|
- lib/apotomo/event_handler.rb
|
102
99
|
- lib/apotomo/event_methods.rb
|
@@ -109,6 +106,7 @@ files:
|
|
109
106
|
- lib/apotomo/rails/view_methods.rb
|
110
107
|
- lib/apotomo/request_processor.rb
|
111
108
|
- lib/apotomo/stateful_widget.rb
|
109
|
+
- lib/apotomo/test_case.rb
|
112
110
|
- lib/apotomo/transition.rb
|
113
111
|
- lib/apotomo/tree_node.rb
|
114
112
|
- lib/apotomo/version.rb
|
@@ -120,72 +118,72 @@ files:
|
|
120
118
|
- lib/generators/apotomo/templates/widget.rb
|
121
119
|
- lib/generators/apotomo/templates/widget_test.rb
|
122
120
|
- lib/generators/apotomo/widget_generator.rb
|
123
|
-
-
|
124
|
-
- test/fixtures/mouse/eating.html.erb
|
121
|
+
- lib/tasks.rake
|
125
122
|
- test/fixtures/mouse/make_me_squeak.html.erb
|
126
|
-
- test/fixtures/mouse/
|
123
|
+
- test/fixtures/mouse/content.html.erb
|
127
124
|
- test/fixtures/mouse/educate.html.erb
|
125
|
+
- test/fixtures/mouse/feed.html.erb
|
128
126
|
- test/fixtures/mouse/snuggle.html.erb
|
129
|
-
- test/fixtures/mouse/
|
127
|
+
- test/fixtures/mouse/eating.html.erb
|
128
|
+
- test/fixtures/mouse/posing.html.erb
|
130
129
|
- test/fixtures/application_widget_tree.rb
|
131
|
-
- test/rails/view_methods_test.rb
|
132
|
-
- test/rails/controller_methods_test.rb
|
133
|
-
- test/rails/view_helper_test.rb
|
134
|
-
- test/rails/widget_generator_test.rb
|
135
|
-
- test/rails/rails_integration_test.rb
|
136
130
|
- test/test_helper.rb
|
137
|
-
- test/support/test_case_methods.rb
|
138
|
-
- test/dummy/config/application.rb
|
139
|
-
- test/dummy/config/initializers/session_store.rb
|
140
|
-
- test/dummy/config/initializers/mime_types.rb
|
141
|
-
- test/dummy/config/initializers/secret_token.rb
|
142
|
-
- test/dummy/config/initializers/inflections.rb
|
143
|
-
- test/dummy/config/initializers/backtrace_silencers.rb
|
144
|
-
- test/dummy/config/locales/en.yml
|
145
|
-
- test/dummy/config/routes.rb
|
146
|
-
- test/dummy/config/boot.rb
|
147
|
-
- test/dummy/config/environment.rb
|
148
|
-
- test/dummy/config/environments/production.rb
|
149
|
-
- test/dummy/config/environments/test.rb
|
150
|
-
- test/dummy/config/environments/development.rb
|
151
|
-
- test/dummy/config/database.yml
|
152
|
-
- test/dummy/script/rails
|
153
|
-
- test/dummy/config.ru
|
154
|
-
- test/dummy/db/test.sqlite3
|
155
131
|
- test/dummy/Rakefile
|
156
|
-
- test/dummy/
|
157
|
-
- test/dummy/
|
158
|
-
- test/dummy/
|
132
|
+
- test/dummy/app/controllers/application_controller.rb
|
133
|
+
- test/dummy/app/helpers/application_helper.rb
|
134
|
+
- test/dummy/app/views/layouts/application.html.erb
|
159
135
|
- test/dummy/public/404.html
|
136
|
+
- test/dummy/public/javascripts/prototype.js
|
160
137
|
- test/dummy/public/javascripts/controls.js
|
138
|
+
- test/dummy/public/javascripts/effects.js
|
139
|
+
- test/dummy/public/javascripts/dragdrop.js
|
161
140
|
- test/dummy/public/javascripts/application.js
|
162
141
|
- test/dummy/public/javascripts/rails.js
|
163
|
-
- test/dummy/public/
|
164
|
-
- test/dummy/public/
|
165
|
-
- test/dummy/public/
|
166
|
-
- test/dummy/
|
167
|
-
- test/dummy/
|
168
|
-
- test/dummy/
|
169
|
-
- test/
|
170
|
-
- test/
|
171
|
-
- test/
|
172
|
-
- test/
|
173
|
-
- test/
|
142
|
+
- test/dummy/public/422.html
|
143
|
+
- test/dummy/public/favicon.ico
|
144
|
+
- test/dummy/public/500.html
|
145
|
+
- test/dummy/config.ru
|
146
|
+
- test/dummy/config/environments/test.rb
|
147
|
+
- test/dummy/config/environments/production.rb
|
148
|
+
- test/dummy/config/environments/development.rb
|
149
|
+
- test/dummy/config/database.yml
|
150
|
+
- test/dummy/config/boot.rb
|
151
|
+
- test/dummy/config/locales/en.yml
|
152
|
+
- test/dummy/config/environment.rb
|
153
|
+
- test/dummy/config/initializers/secret_token.rb
|
154
|
+
- test/dummy/config/initializers/backtrace_silencers.rb
|
155
|
+
- test/dummy/config/initializers/session_store.rb
|
156
|
+
- test/dummy/config/initializers/mime_types.rb
|
157
|
+
- test/dummy/config/initializers/inflections.rb
|
158
|
+
- test/dummy/config/application.rb
|
159
|
+
- test/dummy/config/routes.rb
|
160
|
+
- test/dummy/db/test.sqlite3
|
161
|
+
- test/dummy/script/rails
|
162
|
+
- test/support/test_case_methods.rb
|
163
|
+
- test/rails/rails_integration_test.rb
|
164
|
+
- test/rails/view_methods_test.rb
|
165
|
+
- test/rails/controller_methods_test.rb
|
166
|
+
- test/rails/view_helper_test.rb
|
167
|
+
- test/rails/widget_generator_test.rb
|
168
|
+
- test/unit/onfire_integration_test.rb
|
174
169
|
- test/unit/invoke_test.rb
|
175
|
-
- test/unit/
|
176
|
-
- test/unit/test_tab_panel.rb
|
177
|
-
- test/unit/test_jump_to_state.rb
|
170
|
+
- test/unit/request_processor_test.rb
|
178
171
|
- test/unit/render_test.rb
|
172
|
+
- test/unit/test_case_test.rb
|
179
173
|
- test/unit/apotomo_test.rb
|
180
|
-
- test/unit/request_processor_test.rb
|
181
|
-
- test/unit/test_caching.rb
|
182
174
|
- test/unit/javascript_generator_test.rb
|
183
|
-
- test/unit/
|
175
|
+
- test/unit/stateful_widget_test.rb
|
176
|
+
- test/unit/event_methods_test.rb
|
184
177
|
- test/unit/persistence_test.rb
|
178
|
+
- test/unit/event_handler_test.rb
|
185
179
|
- test/unit/transition_test.rb
|
186
180
|
- test/unit/event_test.rb
|
187
|
-
- test/unit/event_methods_test.rb
|
188
181
|
- test/unit/widget_test.rb
|
182
|
+
- test/unit/widget_shortcuts_test.rb
|
183
|
+
- test/unit/test_tab_panel.rb
|
184
|
+
- test/unit/test_addressing.rb
|
185
|
+
- test/unit/container_test.rb
|
186
|
+
- test/unit/test_jump_to_state.rb
|
189
187
|
has_rdoc: true
|
190
188
|
homepage: http://apotomo.de
|
191
189
|
licenses: []
|
@@ -206,13 +204,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
206
204
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
207
205
|
none: false
|
208
206
|
requirements:
|
209
|
-
- - "
|
207
|
+
- - ">="
|
210
208
|
- !ruby/object:Gem::Version
|
211
209
|
segments:
|
212
|
-
-
|
213
|
-
|
214
|
-
- 1
|
215
|
-
version: 1.3.1
|
210
|
+
- 0
|
211
|
+
version: "0"
|
216
212
|
requirements: []
|
217
213
|
|
218
214
|
rubyforge_project:
|
@@ -221,69 +217,68 @@ signing_key:
|
|
221
217
|
specification_version: 3
|
222
218
|
summary: Web components for Rails.
|
223
219
|
test_files:
|
224
|
-
- test/fixtures/mouse/feed.html.erb
|
225
|
-
- test/fixtures/mouse/eating.html.erb
|
226
220
|
- test/fixtures/mouse/make_me_squeak.html.erb
|
227
|
-
- test/fixtures/mouse/
|
221
|
+
- test/fixtures/mouse/content.html.erb
|
228
222
|
- test/fixtures/mouse/educate.html.erb
|
223
|
+
- test/fixtures/mouse/feed.html.erb
|
229
224
|
- test/fixtures/mouse/snuggle.html.erb
|
230
|
-
- test/fixtures/mouse/
|
225
|
+
- test/fixtures/mouse/eating.html.erb
|
226
|
+
- test/fixtures/mouse/posing.html.erb
|
231
227
|
- test/fixtures/application_widget_tree.rb
|
232
|
-
- test/rails/view_methods_test.rb
|
233
|
-
- test/rails/controller_methods_test.rb
|
234
|
-
- test/rails/view_helper_test.rb
|
235
|
-
- test/rails/widget_generator_test.rb
|
236
|
-
- test/rails/rails_integration_test.rb
|
237
228
|
- test/test_helper.rb
|
238
|
-
- test/support/test_case_methods.rb
|
239
|
-
- test/dummy/config/application.rb
|
240
|
-
- test/dummy/config/initializers/session_store.rb
|
241
|
-
- test/dummy/config/initializers/mime_types.rb
|
242
|
-
- test/dummy/config/initializers/secret_token.rb
|
243
|
-
- test/dummy/config/initializers/inflections.rb
|
244
|
-
- test/dummy/config/initializers/backtrace_silencers.rb
|
245
|
-
- test/dummy/config/locales/en.yml
|
246
|
-
- test/dummy/config/routes.rb
|
247
|
-
- test/dummy/config/boot.rb
|
248
|
-
- test/dummy/config/environment.rb
|
249
|
-
- test/dummy/config/environments/production.rb
|
250
|
-
- test/dummy/config/environments/test.rb
|
251
|
-
- test/dummy/config/environments/development.rb
|
252
|
-
- test/dummy/config/database.yml
|
253
|
-
- test/dummy/script/rails
|
254
|
-
- test/dummy/config.ru
|
255
|
-
- test/dummy/db/test.sqlite3
|
256
229
|
- test/dummy/Rakefile
|
257
|
-
- test/dummy/
|
258
|
-
- test/dummy/
|
259
|
-
- test/dummy/
|
230
|
+
- test/dummy/app/controllers/application_controller.rb
|
231
|
+
- test/dummy/app/helpers/application_helper.rb
|
232
|
+
- test/dummy/app/views/layouts/application.html.erb
|
260
233
|
- test/dummy/public/404.html
|
234
|
+
- test/dummy/public/javascripts/prototype.js
|
261
235
|
- test/dummy/public/javascripts/controls.js
|
236
|
+
- test/dummy/public/javascripts/effects.js
|
237
|
+
- test/dummy/public/javascripts/dragdrop.js
|
262
238
|
- test/dummy/public/javascripts/application.js
|
263
239
|
- test/dummy/public/javascripts/rails.js
|
264
|
-
- test/dummy/public/
|
265
|
-
- test/dummy/public/
|
266
|
-
- test/dummy/public/
|
267
|
-
- test/dummy/
|
268
|
-
- test/dummy/
|
269
|
-
- test/dummy/
|
270
|
-
- test/
|
271
|
-
- test/
|
272
|
-
- test/
|
273
|
-
- test/
|
274
|
-
- test/
|
240
|
+
- test/dummy/public/422.html
|
241
|
+
- test/dummy/public/favicon.ico
|
242
|
+
- test/dummy/public/500.html
|
243
|
+
- test/dummy/config.ru
|
244
|
+
- test/dummy/config/environments/test.rb
|
245
|
+
- test/dummy/config/environments/production.rb
|
246
|
+
- test/dummy/config/environments/development.rb
|
247
|
+
- test/dummy/config/database.yml
|
248
|
+
- test/dummy/config/boot.rb
|
249
|
+
- test/dummy/config/locales/en.yml
|
250
|
+
- test/dummy/config/environment.rb
|
251
|
+
- test/dummy/config/initializers/secret_token.rb
|
252
|
+
- test/dummy/config/initializers/backtrace_silencers.rb
|
253
|
+
- test/dummy/config/initializers/session_store.rb
|
254
|
+
- test/dummy/config/initializers/mime_types.rb
|
255
|
+
- test/dummy/config/initializers/inflections.rb
|
256
|
+
- test/dummy/config/application.rb
|
257
|
+
- test/dummy/config/routes.rb
|
258
|
+
- test/dummy/db/test.sqlite3
|
259
|
+
- test/dummy/script/rails
|
260
|
+
- test/support/test_case_methods.rb
|
261
|
+
- test/rails/rails_integration_test.rb
|
262
|
+
- test/rails/view_methods_test.rb
|
263
|
+
- test/rails/controller_methods_test.rb
|
264
|
+
- test/rails/view_helper_test.rb
|
265
|
+
- test/rails/widget_generator_test.rb
|
266
|
+
- test/unit/onfire_integration_test.rb
|
275
267
|
- test/unit/invoke_test.rb
|
276
|
-
- test/unit/
|
277
|
-
- test/unit/test_tab_panel.rb
|
278
|
-
- test/unit/test_jump_to_state.rb
|
268
|
+
- test/unit/request_processor_test.rb
|
279
269
|
- test/unit/render_test.rb
|
270
|
+
- test/unit/test_case_test.rb
|
280
271
|
- test/unit/apotomo_test.rb
|
281
|
-
- test/unit/request_processor_test.rb
|
282
|
-
- test/unit/test_caching.rb
|
283
272
|
- test/unit/javascript_generator_test.rb
|
284
|
-
- test/unit/
|
273
|
+
- test/unit/stateful_widget_test.rb
|
274
|
+
- test/unit/event_methods_test.rb
|
285
275
|
- test/unit/persistence_test.rb
|
276
|
+
- test/unit/event_handler_test.rb
|
286
277
|
- test/unit/transition_test.rb
|
287
278
|
- test/unit/event_test.rb
|
288
|
-
- test/unit/event_methods_test.rb
|
289
279
|
- test/unit/widget_test.rb
|
280
|
+
- test/unit/widget_shortcuts_test.rb
|
281
|
+
- test/unit/test_tab_panel.rb
|
282
|
+
- test/unit/test_addressing.rb
|
283
|
+
- test/unit/container_test.rb
|
284
|
+
- test/unit/test_jump_to_state.rb
|
data/lib/apotomo/caching.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
# Introduces caching of rendered state views into the StatefulWidget.
|
2
|
-
module Apotomo::Caching
|
3
|
-
|
4
|
-
def self.included(base) #:nodoc:
|
5
|
-
base.class_eval do
|
6
|
-
extend ClassMethods
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
|
11
|
-
module ClassMethods
|
12
|
-
# If <tt>version_proc</tt> is omitted, Apotomo provides some basic caching
|
13
|
-
# mechanism: the state view rendered for <tt>state</tt> will be cached as long
|
14
|
-
# as you (or e.g. an EventHandler) calls #dirty!. It will then be re-rendered
|
15
|
-
# and cached again.
|
16
|
-
# You may override that to provide fine-grained caching, with multiple cache versions
|
17
|
-
# for the same state.
|
18
|
-
def cache(state, version_proc=:cache_version)
|
19
|
-
super(state, version_proc)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def cache_version
|
24
|
-
@version ||= 0
|
25
|
-
{:v => @version}
|
26
|
-
end
|
27
|
-
|
28
|
-
def increment_version
|
29
|
-
@version += 1
|
30
|
-
end
|
31
|
-
|
32
|
-
# Instruct caching to re-render all cached state views.
|
33
|
-
def dirty!
|
34
|
-
increment_version
|
35
|
-
end
|
36
|
-
|
37
|
-
end
|
@@ -1,90 +0,0 @@
|
|
1
|
-
module Apotomo
|
2
|
-
module DeepLinkMethods
|
3
|
-
def self.included(base)
|
4
|
-
base.initialize_hooks << :initialize_deep_link_for
|
5
|
-
end
|
6
|
-
|
7
|
-
|
8
|
-
# Called in StatefulWidget's constructor.
|
9
|
-
def initialize_deep_link_for(id, start_states, opts)
|
10
|
-
#add_deep_link if opts[:is_url_listener] ### DISCUSS: remove #add_de
|
11
|
-
end
|
12
|
-
|
13
|
-
def responds_to_url_change?
|
14
|
-
evt_table.all_handlers_for(:urlChange, name).size > 0
|
15
|
-
end
|
16
|
-
|
17
|
-
|
18
|
-
### DISCUSS: private? rename to compute_url_fragment_for ?
|
19
|
-
# Computes the fragment part of the widget's url by querying all widgets up to root.
|
20
|
-
# Widgets managing a certain state will usually insert state recovery information
|
21
|
-
# via local_fragment.
|
22
|
-
def url_fragment_for(local_portion=nil, portions=[])
|
23
|
-
local_portion = local_fragment if responds_to_url_change? and local_portion.nil?
|
24
|
-
|
25
|
-
portions.unshift(local_portion) # prepend portions as we move up.
|
26
|
-
|
27
|
-
return portions.compact.join("/") if root?
|
28
|
-
|
29
|
-
parent.url_fragment_for(nil, portions)
|
30
|
-
end
|
31
|
-
|
32
|
-
|
33
|
-
# Called when widget :is_url_listener. Adds the local url fragment portion to the url.
|
34
|
-
def local_fragment
|
35
|
-
#"#{local_fragment_key}=#{state_name}"
|
36
|
-
end
|
37
|
-
|
38
|
-
# Key found in the url fragment, pointing to the local fragment.
|
39
|
-
#def local_fragment_key
|
40
|
-
# name
|
41
|
-
#end
|
42
|
-
|
43
|
-
|
44
|
-
# Called by DeepLinkWidget#process to query if we're involved in an URL change.
|
45
|
-
# Do return false if you're not interested in the change.
|
46
|
-
#
|
47
|
-
# This especially means:
|
48
|
-
# * the fragment doesn't include you or is empty
|
49
|
-
# fragment[name].blank?
|
50
|
-
# * your portion in the fragment didn't change
|
51
|
-
# tab=first/content=html vs. tab=first/content=markdown
|
52
|
-
# fragment[:tab] != @active_tab
|
53
|
-
def responds_to_url_change_for?(fragment)
|
54
|
-
end
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
class UrlFragment
|
59
|
-
attr_reader :fragment
|
60
|
-
|
61
|
-
def initialize(fragment)
|
62
|
-
@fragment = fragment || ""
|
63
|
-
end
|
64
|
-
|
65
|
-
def to_s
|
66
|
-
fragment.to_s
|
67
|
-
end
|
68
|
-
|
69
|
-
def blank?
|
70
|
-
fragment.blank?
|
71
|
-
end
|
72
|
-
|
73
|
-
### TODO: make path separator configurable.
|
74
|
-
def [](key)
|
75
|
-
if path_portion = fragment.split("/").find {|i| i.include?(key.to_s)}
|
76
|
-
return path_portion.sub("#{key}=", "")
|
77
|
-
end
|
78
|
-
|
79
|
-
nil
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
# Query object for the url fragment. Use this to retrieve state information from the
|
84
|
-
# deep link.
|
85
|
-
def url_fragment
|
86
|
-
UrlFragment.new(param(:deep_link))
|
87
|
-
end
|
88
|
-
|
89
|
-
end
|
90
|
-
end
|
data/test/unit/test_caching.rb
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class ApotomoCachingTest < Test::Unit::TestCase
|
4
|
-
include Apotomo::UnitTestCase
|
5
|
-
|
6
|
-
def setup
|
7
|
-
super
|
8
|
-
@controller.session= {}
|
9
|
-
@cc = CachingCell.new('caching_cell', :start)
|
10
|
-
@cc.controller = @controller
|
11
|
-
end
|
12
|
-
|
13
|
-
|
14
|
-
def test_caching_with_instance_version_proc
|
15
|
-
unless ActionController::Base.cache_configured?
|
16
|
-
throw Exception.new "cache_configured? returned false. You may enable caching in your config/environments/test.rb to make this test pass."
|
17
|
-
return
|
18
|
-
end
|
19
|
-
c1 = @cc.invoke
|
20
|
-
c2 = @cc.invoke
|
21
|
-
assert_equal c1, c2
|
22
|
-
|
23
|
-
@cc.dirty!
|
24
|
-
|
25
|
-
c3 = @cc.invoke
|
26
|
-
assert c2 != c3
|
27
|
-
end
|
28
|
-
|
29
|
-
end
|
30
|
-
|
31
|
-
|
32
|
-
class CachingCell < Apotomo::StatefulWidget
|
33
|
-
|
34
|
-
cache :cached_state
|
35
|
-
|
36
|
-
transition :in => :cached_state
|
37
|
-
|
38
|
-
|
39
|
-
def start
|
40
|
-
jump_to_state :cached_state
|
41
|
-
end
|
42
|
-
|
43
|
-
def cached_state
|
44
|
-
@counter ||= 0
|
45
|
-
@counter += 1
|
46
|
-
"#{@counter}"
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
def not_cached_state
|
51
|
-
"i'm really static"
|
52
|
-
end
|
53
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
# fixture:
|
4
|
-
module My
|
5
|
-
class TestCell < Apotomo::StatefulWidget
|
6
|
-
def a_state
|
7
|
-
"a_state"
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
class TestWidget < Apotomo::StatefulWidget
|
12
|
-
def a_state
|
13
|
-
"a_state"
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
class MyTestWidgetTree < Apotomo::WidgetTree
|
19
|
-
def draw(root)
|
20
|
-
root << widget('apotomo/stateful_widget', :widget_content, 'widget_one')
|
21
|
-
root << cell(:my_test, :a_state, 'my_test_cell')
|
22
|
-
root << switch('my_switch') << widget('apotomo/stateful_widget', :widget_content, :child_widget)
|
23
|
-
root << section('my_section')
|
24
|
-
root << widget('apotomo/stateful_widget', :widget_content, :widget_three)
|
25
|
-
#root ### FIXME! find a way to return nothing by default.
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
|
30
|
-
class WidgetShortcutsTest < Test::Unit::TestCase
|
31
|
-
include Apotomo::UnitTestCase
|
32
|
-
|
33
|
-
|
34
|
-
def test_cell
|
35
|
-
assert_kind_of My::TestCell, cell("my/test", :a_state, 'my_test_cell')
|
36
|
-
end
|
37
|
-
|
38
|
-
def test_widget
|
39
|
-
w = widget("my/test_widget", :a_state, 'my_test_cell')
|
40
|
-
assert_kind_of My::TestWidget, w
|
41
|
-
assert_equal "my_test_cell", w.name
|
42
|
-
end
|
43
|
-
|
44
|
-
end
|