fortitude 0.0.7 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +73 -0
  3. data/CONTRIBUTORS.md +17 -0
  4. data/ext/com/fortituderuby/ext/fortitude/FortitudeNativeLibrary.java +23 -7
  5. data/ext/fortitude_native_ext/fortitude_native_ext.c +91 -54
  6. data/lib/fortitude/doctypes/html4.rb +4 -0
  7. data/lib/fortitude/doctypes/html5.rb +4 -0
  8. data/lib/fortitude/doctypes/unknown_doctype.rb +4 -0
  9. data/lib/fortitude/doctypes/xhtml10.rb +4 -0
  10. data/lib/fortitude/doctypes/xhtml11.rb +4 -0
  11. data/lib/fortitude/erector.rb +1 -0
  12. data/lib/fortitude/errors.rb +16 -0
  13. data/lib/fortitude/extensions/fortitude_ruby_ext.rb +27 -12
  14. data/lib/fortitude/method_templates/assign_locals_from_template.rb.smpl +2 -0
  15. data/lib/fortitude/method_templates/need_assignment_template.rb.smpl +2 -2
  16. data/lib/fortitude/method_templates/simple_compiled_template.rb +94 -0
  17. data/lib/fortitude/method_templates/tag_method_template.rb.smpl +4 -4
  18. data/lib/fortitude/method_templates/text_method_template.rb.smpl +2 -2
  19. data/lib/fortitude/rails/railtie.rb +5 -1
  20. data/lib/fortitude/rails/rendering_methods.rb +66 -47
  21. data/lib/fortitude/rails/template_handler.rb +0 -1
  22. data/lib/fortitude/rendering_context.rb +2 -2
  23. data/lib/fortitude/tags/tag.rb +4 -3
  24. data/lib/fortitude/version.rb +1 -1
  25. data/lib/fortitude/widget.rb +1 -1
  26. data/lib/fortitude/widget/content.rb +1 -1
  27. data/lib/fortitude/widget/integration.rb +12 -3
  28. data/lib/fortitude/widget/localization.rb +1 -37
  29. data/lib/fortitude/widget/needs.rb +41 -12
  30. data/lib/fortitude/widget/rendering.rb +25 -7
  31. data/lib/fortitude/widget/start_and_end_comments.rb +1 -0
  32. data/lib/fortitude/widget/tags.rb +2 -1
  33. data/lib/fortitude/widget/widget_class_inheritable_attributes.rb +1 -0
  34. data/lib/fortitude_jruby_native_ext.jar +0 -0
  35. data/spec/helpers/system_helpers.rb +4 -0
  36. data/spec/rails/class_loading_system_spec.rb +10 -2
  37. data/spec/rails/development_mode_system_spec.rb +91 -0
  38. data/spec/rails/erector_coexistence_system_spec.rb +16 -0
  39. data/spec/rails/layouts_system_spec.rb +8 -3
  40. data/spec/rails/rendering_system_spec.rb +24 -2
  41. data/spec/rails/templates/class_loading_system_spec/app/controllers/class_loading_system_spec_controller.rb +6 -2
  42. data/spec/rails/templates/class_loading_system_spec/app/views/class_loading_system_spec/_foo.rb +5 -0
  43. data/spec/rails/templates/class_loading_system_spec/app/views/class_loading_system_spec/bar.html.rb +5 -0
  44. data/spec/rails/templates/class_loading_system_spec/app/views/class_loading_system_spec/bar.rb +5 -0
  45. data/spec/rails/templates/class_loading_system_spec/app/views/class_loading_system_spec/foo.rb +5 -0
  46. data/spec/rails/templates/development_mode_system_spec/app/controllers/development_mode_system_spec_controller.rb +4 -0
  47. data/spec/rails/templates/development_mode_system_spec/app/views/base.rb +5 -0
  48. data/spec/rails/templates/development_mode_system_spec/app/views/development_mode_system_spec/form.rb +11 -0
  49. data/spec/rails/templates/erector_coexistence_system_spec/app/controllers/erector_coexistence_system_spec_controller.rb +16 -0
  50. data/spec/rails/templates/erector_coexistence_system_spec/app/views/erector_widget.rb +5 -0
  51. data/spec/rails/templates/erector_coexistence_system_spec/app/views/fortitude_widget.rb +5 -0
  52. data/spec/rails/templates/localization_system_spec/app/views/localization_system_spec/content_method.rb +2 -0
  53. data/spec/rails/templates/rendering_system_spec/app/controllers/rendering_system_spec_controller.rb +14 -1
  54. data/spec/rails/templates/rendering_system_spec/app/helpers/application_helper.rb +5 -0
  55. data/spec/rails/templates/rendering_system_spec/app/views/widget_to_render_class_only.rb +5 -0
  56. data/spec/rails/templates/rendering_system_spec/app/views/widget_to_render_with_helper.rb +5 -0
  57. data/spec/system/doctypes_system_spec.rb +30 -8
  58. data/spec/system/erector_compatibility_system_spec.rb +27 -0
  59. data/spec/system/localization_system_spec.rb +4 -0
  60. data/spec/system/needs_system_spec.rb +31 -0
  61. data/spec/system/rebuild_notifications_system_spec.rb +180 -85
  62. data/spec/system/setting_inheritance_system_spec.rb +47 -0
  63. data/spec/system/static_method_system_spec.rb +2 -0
  64. data/spec/system/tag_rendering_system_spec.rb +41 -0
  65. data/spec/system/void_tags_system_spec.rb +1 -0
  66. data/spec/system/yield_system_spec.rb +188 -0
  67. metadata +27 -5
  68. data/lib/fortitude/method_templates/simple_template.rb +0 -50
  69. data/spec/rails/templates/class_loading_system_spec/app/views/class_loading_system_spec/_underscore_widget.rb +0 -11
@@ -29,5 +29,21 @@ describe "Erector coexistence support", :type => :rails do
29
29
  it "should be able to render an Erector widget in app/v/views" do
30
30
  expect_match("erector_widget_in_app_v_views", /<p\s+class\s*=\s*"some_class"\s*>this is Erector: foo = quux<\/p>/)
31
31
  end
32
+
33
+ it "should be able to render a Fortitude widget using render :widget" do
34
+ expect_match("render_widget_fortitude", /this is a Fortitude widget/)
35
+ end
36
+
37
+ it "should be able to render an Erector widget using render :widget" do
38
+ expect_match("render_widget_erector", /this is an Erector widget/, :no_layout => true)
39
+ end
40
+
41
+ it "should be able to render a Fortitude widget with just a class using render :widget" do
42
+ expect_match("render_widget_fortitude_class", /this is a Fortitude widget/)
43
+ end
44
+
45
+ it "should be able to render an Erector widget with just a class using render :widget" do
46
+ expect_match("render_widget_erector_class", /this is an Erector widget/, :no_layout => true)
47
+ end
32
48
  end
33
49
  end
@@ -41,9 +41,14 @@ describe "Rails layout support", :type => :rails do
41
41
  end
42
42
 
43
43
  it "should let you turn off the layout with render :widget" do
44
- data = get("render_widget_without_layout")
45
- data.should_not match(/default_layout_erb/i)
46
- data.should match(/this is the_render_widget/i)
44
+ unless rails_server.rails_version =~ /^3\.[01]\./
45
+ # Rails 3.0 and 3.1 simply don't pass the ":layout => false" option specified in the controller through to
46
+ # the renderer we add using ::ActionController.add_renderer. There's really nothing we can do about this,
47
+ # so we let this one particular case fail; it seems like a bug in Rails, not in our code.
48
+ data = get("render_widget_without_layout")
49
+ data.should_not match(/default_layout_erb/i)
50
+ data.should match(/this is the_render_widget/i)
51
+ end
47
52
  end
48
53
 
49
54
  it "should let you pick an alternate layout for render :widget" do
@@ -15,9 +15,31 @@ describe "Rails rendering support", :type => :rails do
15
15
  expect(data).to match(/oop_rails_server_base_template/)
16
16
  end
17
17
 
18
+ it "should always set a content-type of text/html when using 'render :widget'" do
19
+ response = get_response("render_widget")
20
+ expect(response['Content-Type']).to match(/^text\/html/)
21
+ end
22
+
23
+ it "should let you use view helpers from within a widget passed to 'render :widget =>'" do
24
+ expect_match("render_widget_with_helper", /hello from a widget named Judy/)
25
+ end
26
+
27
+ it "should let you specify just a widget class with 'render :widget =>'" do
28
+ expect_match("render_widget_class_only", /hello from a simple widget/)
29
+ end
30
+
31
+ it "should let you specify just a widget class with 'render :widget =>', and pass assigns to it" do
32
+ expect_match("render_widget_class_and_assigns", /hello from a widget named Yaravan/)
33
+ end
34
+
18
35
  it "should let you omit the layout with 'render :widget =>', if you ask for it" do
19
- data = expect_match("render_widget_without_layout", /hello from a widget named Fred/, :no_layout => true)
20
- expect(data).not_to match(/oop_rails_server_base_template/)
36
+ unless rails_server.rails_version =~ /^3\.[01]\./
37
+ # Rails 3.0 and 3.1 simply don't pass the ":layout => false" option specified in the controller through to
38
+ # the renderer we add using ::ActionController.add_renderer. There's really nothing we can do about this,
39
+ # so we let this one particular case fail; it seems like a bug in Rails, not in our code.
40
+ data = expect_match("render_widget_without_layout", /hello from a widget named Fred/, :no_layout => true)
41
+ expect(data).not_to match(/oop_rails_server_base_template/)
42
+ end
21
43
  end
22
44
 
23
45
  it "should set the Content-Type to text/html when using render :widget" do
@@ -53,8 +53,12 @@ class ClassLoadingSystemSpecController < ApplicationController
53
53
  # nothing here
54
54
  end
55
55
 
56
- def underscore_widget
57
- render :text => Views::ClassLoadingSystemSpec::UnderscoreWidget.data
56
+ def foo
57
+ # nothing here
58
+ end
59
+
60
+ def bar
61
+ # nothing here
58
62
  end
59
63
 
60
64
  def require_loaded_underscore_widget_without_views
@@ -0,0 +1,5 @@
1
+ class Views::ClassLoadingSystemSpec::Foo < Fortitude::Widgets::Html5
2
+ def content
3
+ p "foo WITH underscore"
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Views::ClassLoadingSystemSpec::Bar < Fortitude::Widgets::Html5
2
+ def content
3
+ p "bar WITH html"
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Views::ClassLoadingSystemSpec::Bar < Fortitude::Widgets::Html5
2
+ def content
3
+ p "bar WITHOUT html"
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Views::ClassLoadingSystemSpec::Foo < Fortitude::Widgets::Html5
2
+ def content
3
+ p "foo WITHOUT underscore"
4
+ end
5
+ end
@@ -15,6 +15,10 @@ class DevelopmentModeSystemSpecController < ApplicationController
15
15
  # nothing here
16
16
  end
17
17
 
18
+ def edit
19
+ # nothing here
20
+ end
21
+
18
22
  def mailer_view_test
19
23
  DevelopmentModeMailer.mailer_view_test.deliver
20
24
  end
@@ -0,0 +1,5 @@
1
+ module Views
2
+ class Base < Fortitude::Widget
3
+ doctype :html5
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ module Views
2
+ module DevelopmentModeSystemSpec
3
+ class Form < Views::Base
4
+ needs :label
5
+
6
+ def content
7
+ p(label)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -16,4 +16,20 @@ class ErectorCoexistenceSystemSpecController < ApplicationController
16
16
  def erector_widget_in_app_v_views
17
17
  @foo = "quux"
18
18
  end
19
+
20
+ def render_widget_fortitude
21
+ render :widget => ::Views::FortitudeWidget.new
22
+ end
23
+
24
+ def render_widget_erector
25
+ render :widget => ::Views::ErectorWidget.new
26
+ end
27
+
28
+ def render_widget_fortitude_class
29
+ render :widget => ::Views::FortitudeWidget
30
+ end
31
+
32
+ def render_widget_erector_class
33
+ render :widget => ::Views::ErectorWidget
34
+ end
19
35
  end
@@ -0,0 +1,5 @@
1
+ class Views::ErectorWidget < Erector::Widget
2
+ def content
3
+ text "this is an Erector widget"
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Views::FortitudeWidget < Fortitude::Widgets::Html5
2
+ def content
3
+ text "this is a Fortitude widget"
4
+ end
5
+ end
@@ -1,4 +1,6 @@
1
1
  class Views::LocalizationSystemSpec::ContentMethod < Fortitude::Widgets::Html5
2
+ use_localized_content_methods true
3
+
2
4
  def localized_content_en
3
5
  text "wassup? this is english"
4
6
  end
@@ -11,6 +11,19 @@ class RenderingSystemSpecController < ApplicationController
11
11
  render :widget => Views::WidgetToRender.new(:name => 'Fred')
12
12
  end
13
13
 
14
+ def render_widget_with_helper
15
+ render :widget => Views::WidgetToRenderWithHelper.new
16
+ end
17
+
18
+ def render_widget_class_only
19
+ render :widget => Views::WidgetToRenderClassOnly
20
+ end
21
+
22
+ def render_widget_class_and_assigns
23
+ @name = 'Yaravan'
24
+ render :widget => Views::WidgetToRender
25
+ end
26
+
14
27
  def render_widget_without_layout
15
28
  render :widget => Views::WidgetToRender.new(:name => 'Fred'), :layout => false
16
29
  end
@@ -28,7 +41,7 @@ class RenderingSystemSpecController < ApplicationController
28
41
  def render_widget_via_inline
29
42
  @name = "Fred"
30
43
  proc = lambda do
31
- p "this is an inline widget named #{shared_variables[:name]}"
44
+ p "this is an inline widget named #{name}"
32
45
  end
33
46
  render :inline => proc, :type => :fortitude
34
47
  end
@@ -0,0 +1,5 @@
1
+ module ApplicationHelper
2
+ def my_name_helper
3
+ "Judy"
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Views::WidgetToRenderClassOnly < Fortitude::Widgets::Html5
2
+ def content
3
+ p "hello from a simple widget"
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Views::WidgetToRenderWithHelper < Fortitude::Widgets::Html5
2
+ def content
3
+ p "hello from a widget named #{my_name_helper}"
4
+ end
5
+ end
@@ -47,56 +47,64 @@ describe "Fortitude doctype support", :type => :system do
47
47
  :allows_dir => false, :allows_background => false, :allows_frame => false, :closes_void_tags => false,
48
48
  :requires_close_void_tags_to_be => nil,
49
49
  :doctype_line => '<!DOCTYPE html>',
50
- :javascript => :none
50
+ :javascript => :none,
51
+ :true_value_has_attribute_value => false
51
52
  },
52
53
 
53
54
  :html4_strict => {
54
55
  :allows_dir => false, :allows_background => false, :allows_frame => false, :closes_void_tags => false,
55
56
  :requires_close_void_tags_to_be => false,
56
57
  :doctype_line => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">',
57
- :javascript => :type
58
+ :javascript => :type,
59
+ :true_value_has_attribute_value => false
58
60
  },
59
61
 
60
62
  :html4_transitional => {
61
63
  :allows_dir => true, :allows_background => true, :allows_frame => false, :closes_void_tags => false,
62
64
  :requires_close_void_tags_to_be => false,
63
65
  :doctype_line => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
64
- :javascript => :type
66
+ :javascript => :type,
67
+ :true_value_has_attribute_value => false
65
68
  },
66
69
 
67
70
  :html4_frameset => {
68
71
  :allows_dir => true, :allows_background => true, :allows_frame => true, :closes_void_tags => false,
69
72
  :requires_close_void_tags_to_be => false,
70
73
  :doctype_line => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">',
71
- :javascript => :type
74
+ :javascript => :type,
75
+ :true_value_has_attribute_value => false
72
76
  },
73
77
 
74
78
  :xhtml10_strict => {
75
79
  :allows_dir => false, :allows_background => false, :allows_frame => false, :closes_void_tags => true,
76
80
  :requires_close_void_tags_to_be => true,
77
81
  :doctype_line => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
78
- :javascript => :type_and_cdata
82
+ :javascript => :type_and_cdata,
83
+ :true_value_has_attribute_value => true
79
84
  },
80
85
 
81
86
  :xhtml10_transitional => {
82
87
  :allows_dir => true, :allows_background => true, :allows_frame => false, :closes_void_tags => true,
83
88
  :requires_close_void_tags_to_be => true,
84
89
  :doctype_line => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
85
- :javascript => :type_and_cdata
90
+ :javascript => :type_and_cdata,
91
+ :true_value_has_attribute_value => true
86
92
  },
87
93
 
88
94
  :xhtml10_frameset => {
89
95
  :allows_dir => true, :allows_background => true, :allows_frame => true, :closes_void_tags => true,
90
96
  :requires_close_void_tags_to_be => true,
91
97
  :doctype_line => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
92
- :javascript => :type_and_cdata
98
+ :javascript => :type_and_cdata,
99
+ :true_value_has_attribute_value => true
93
100
  },
94
101
 
95
102
  :xhtml11 => {
96
103
  :allows_dir => false, :allows_background => false, :allows_frame => false, :closes_void_tags => true,
97
104
  :requires_close_void_tags_to_be => true,
98
105
  :doctype_line => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
99
- :javascript => :type_and_cdata
106
+ :javascript => :type_and_cdata,
107
+ :true_value_has_attribute_value => true
100
108
  }
101
109
  }.each do |doctype, expected_results|
102
110
  describe doctype do
@@ -104,6 +112,20 @@ describe "Fortitude doctype support", :type => :system do
104
112
  @classes_by_doctype[doctype] ||= wc_with_doctype(doctype)
105
113
  }
106
114
 
115
+ it "should #{expected_results[:true_value_has_attribute_value] ? "" : "not "}have an attribute value for attribute values of true" do
116
+ the_widget_class.class_eval do
117
+ def content
118
+ p(:class => true)
119
+ end
120
+ end
121
+
122
+ if expected_results[:true_value_has_attribute_value]
123
+ expect(render(the_widget_class)).to eq("<p class=\"class\"></p>")
124
+ else
125
+ expect(render(the_widget_class)).to eq("<p class></p>")
126
+ end
127
+ end
128
+
107
129
  it "should #{expected_results[:allows_dir] ? "" : "not "}allow <dir>" do
108
130
  the_widget_class.class_eval do
109
131
  def content
@@ -81,4 +81,31 @@ describe "Fortitude Erector compatibility", :type => :system do
81
81
  expect(render(wc.new(:foo => "the_foo", :bar => "the_bar"))).to eq("foo: the_foo, bar: the_bar")
82
82
  end
83
83
  end
84
+
85
+ it "should allow calling #call_block as an alias for #yield_from_widget, but not pass the widget instance" do
86
+ wc_sub = widget_class do
87
+ def content
88
+ text "inner_before"
89
+ call_block
90
+ text "inner_after"
91
+ end
92
+ end
93
+
94
+ wc = widget_class do
95
+ cattr_accessor :other_widget_class
96
+
97
+ def content
98
+ text "before"
99
+ widget other_widget_class do |*args|
100
+ raise "invalid: #{args.inspect}" if args.length > 0
101
+ text "middle"
102
+ end
103
+ text "after"
104
+ end
105
+ end
106
+
107
+ wc.other_widget_class = wc_sub
108
+
109
+ expect(render(wc)).to eq("beforeinner_beforemiddleinner_afterafter")
110
+ end
84
111
  end
@@ -1,6 +1,8 @@
1
1
  describe "Fortitude native (non-Rails) localization support", :type => :system do
2
2
  before :each do
3
3
  @klass = widget_class do
4
+ use_localized_content_methods true
5
+
4
6
  def localized_content_en
5
7
  text "english!"
6
8
  end
@@ -48,6 +50,8 @@ describe "Fortitude native (non-Rails) localization support", :type => :system d
48
50
  @klass = widget_class do
49
51
  attr_accessor :widget_locale
50
52
 
53
+ use_localized_content_methods true
54
+
51
55
  def initialize(attributes = { })
52
56
  self.widget_locale = attributes.delete(:widget_locale)
53
57
  super(attributes)
@@ -16,6 +16,37 @@ describe "Fortitude needs", :type => :system do
16
16
  expect(child.needs(:baz => 'def_baz')).to eq(:foo => required, :bar => required, :baz => 'def_baz')
17
17
  end
18
18
 
19
+ it "should not rebuild 'needs' at all unless you actually use a widget" do
20
+ notifications = [ ]
21
+ ActiveSupport::Notifications.subscribe("fortitude.rebuilding") do |*args|
22
+ notifications << args
23
+ end
24
+
25
+ wc1 = widget_class do
26
+ def content
27
+ p "hello, world"
28
+ end
29
+ end
30
+
31
+ wc2 = widget_class do
32
+ needs :foo, :bar, :baz
33
+
34
+ def content
35
+ p "foo: #{foo}, bar: #{bar}"
36
+ end
37
+ end
38
+
39
+ wc3 = widget_class do
40
+ needs :foo, :bar
41
+
42
+ def content
43
+ p "foo: #{foo}"
44
+ end
45
+ end
46
+
47
+ expect(notifications).to eq([ ])
48
+ end
49
+
19
50
  it "should raise an exception if you try to modify a 'needs' default value" do
20
51
  wc = widget_class do
21
52
  needs :foo, :bar => [ 'a', 'b' ]
@@ -1,157 +1,252 @@
1
1
  describe "Fortitude rebuilding notifications", :type => :system do
2
2
  before :each do
3
- @notifications = [ ]
4
- n = @notifications
5
- ActiveSupport::Notifications.subscribe("fortitude.rebuilding") do |*args|
6
- n << args
3
+ @rebuild_notifications = [ ]
4
+ rbn = @rebuild_notifications
5
+ ActiveSupport::Notifications.subscribe("fortitude.rebuilding") do |name, start, finish, id, payload|
6
+ if payload[:what] == :needs && [ ::Fortitude::Widget, ::SystemHelpers::TestWidgetClass ].include?(payload[:class])
7
+ # So, here's the deal: needs get rebuilt on ::Fortitude::Widget and ::SystemHelpers::TestWidgetClass by
8
+ # whatever example in this file is the *first* one to actually instantiate a widget, and then not past that
9
+ # point, since we never change anything need-related on either of those classes. (Which is really important,
10
+ # or we'd reconfigure Fortitude internally for *all other specs*.)
11
+ #
12
+ # As a result, it's much simpler and more reliable to simply ignore these notifications than try to keep track
13
+ # of which is the first spec to cause these to be rebuilt. Specs below do check things like superclass-subclass
14
+ # needs invalidation, so we're good there too.
15
+ else
16
+ rbn << [ name, start, finish, id, payload ]
17
+ end
18
+ end
19
+
20
+ @invalidating_notifications = [ ]
21
+ ivn = @invalidating_notifications
22
+ ActiveSupport::Notifications.subscribe("fortitude.invalidating") do |name, start, finish, id, payload|
23
+ ivn << [ name, start, finish, id, payload ]
7
24
  end
8
25
 
9
26
  @wc = widget_class
10
27
  end
11
28
 
12
- def expect_notification(expected_payload)
29
+ def expect_rebuild_notification(expected_payload)
30
+ expected_payload = { :class => @wc, :originating_class => @wc }.merge(expected_payload)
31
+ notification = @rebuild_notifications.detect do |(name, start, finish, id, payload)|
32
+ payload == expected_payload
33
+ end
34
+ raise "Can't find rebuild notification with payload #{expected_payload.inspect}; have: #{@rebuild_notifications.inspect} (invalidating: #{@invalidating_notifications.inspect})" unless notification
35
+ @rebuild_notifications.delete(notification)
36
+ end
37
+
38
+ def expect_no_more_rebuild_notifications!(what = nil)
39
+ remaining = @rebuild_notifications
40
+ remaining = remaining.select { |n| n[4][:what] == what } if what
41
+
42
+ if remaining.length > 0
43
+ raise "Had more rebuild notifications that we didn't expect: #{remaining.inspect}"
44
+ end
45
+ end
46
+
47
+ def expect_invalidating_notification(expected_payload)
13
48
  expected_payload = { :class => @wc, :originating_class => @wc }.merge(expected_payload)
14
- notification = @notifications.detect do |(name, start, finish, id, payload)|
49
+ notification = @invalidating_notifications.detect do |(name, start, finish, id, payload)|
15
50
  payload == expected_payload
16
51
  end
17
- raise "Can't find notification with payload #{expected_payload.inspect}; have: #{@notifications.inspect}" unless notification
18
- @notifications.delete(notification)
52
+ raise "Can't find invalidating notification with payload #{expected_payload.inspect}; have: #{@invalidating_notifications.inspect} (rebuilding: #{@rebuild_notifications.inspect})" unless notification
53
+ @invalidating_notifications.delete(notification)
19
54
  end
20
55
 
21
- def expect_no_more_notifications!(what = nil)
22
- remaining = @notifications
56
+ def expect_no_more_invalidating_notifications!(what = nil)
57
+ remaining = @invalidating_notifications
23
58
  remaining = remaining.select { |n| n[4][:what] == what } if what
24
59
 
25
60
  if remaining.length > 0
26
- raise "Had more notifications that we didn't expect: #{remaining.inspect}"
61
+ raise "Had more invalidating notifications that we didn't expect: #{remaining.inspect}"
27
62
  end
28
63
  end
29
64
 
30
65
  describe "text methods" do
31
66
  it "should fire a notification when rebuilding because format_output has changed" do
32
67
  @wc.format_output true
33
- expect_notification(:what => :text_methods, :why => :format_output_changed)
34
- expect_no_more_notifications!(:text_methods)
68
+ expect_rebuild_notification(:what => :text_methods, :why => :format_output_changed)
69
+ expect_no_more_rebuild_notifications!(:text_methods)
35
70
 
36
71
  @wc.format_output false
37
- expect_notification(:what => :text_methods, :why => :format_output_changed)
38
- expect_no_more_notifications!(:text_methods)
72
+ expect_rebuild_notification(:what => :text_methods, :why => :format_output_changed)
73
+ expect_no_more_rebuild_notifications!(:text_methods)
39
74
  end
40
75
  end
41
76
 
42
77
  describe "needs" do
43
- it "should fire a notification when rebuilding because a need was declared" do
78
+ it "should fire an notification when invalidating because a need was declared" do
44
79
  @wc.needs :foo
45
- expect_notification(:what => :needs, :why => :need_declared)
46
- expect_no_more_notifications!(:needs)
80
+ expect_invalidating_notification(:what => :needs, :why => :need_declared)
81
+ expect_no_more_invalidating_notifications!(:needs)
47
82
 
48
83
  @wc.needs :bar => :baz
49
- expect_notification(:what => :needs, :why => :need_declared)
50
- expect_no_more_notifications!(:needs)
84
+ expect_invalidating_notification(:what => :needs, :why => :need_declared)
85
+ expect_no_more_invalidating_notifications!(:needs)
51
86
  end
52
87
 
53
- it "should fire a notification when rebuilding because extra_assigns was changed" do
88
+ it "should fire a notification when invalidating because extra_assigns was changed" do
54
89
  @wc.extra_assigns :use
55
- expect_notification(:what => :needs, :why => :extra_assigns_changed)
56
- expect_no_more_notifications!(:needs)
90
+ expect_invalidating_notification(:what => :needs, :why => :extra_assigns_changed)
91
+ expect_no_more_invalidating_notifications!(:needs)
57
92
 
58
93
  @wc.extra_assigns :error
59
- expect_notification(:what => :needs, :why => :extra_assigns_changed)
60
- expect_no_more_notifications!(:needs)
94
+ expect_invalidating_notification(:what => :needs, :why => :extra_assigns_changed)
95
+ expect_no_more_invalidating_notifications!(:needs)
61
96
  end
62
97
 
63
- it "should fire a notification when rebuilding because use_instance_variables_for_assigns was changed" do
98
+ it "should fire a notification when invalidating because use_instance_variables_for_assigns was changed" do
64
99
  @wc.use_instance_variables_for_assigns true
65
- expect_notification(:what => :needs, :why => :use_instance_variables_for_assigns_changed)
66
- expect_no_more_notifications!(:needs)
100
+ expect_invalidating_notification(:what => :needs, :why => :use_instance_variables_for_assigns_changed)
101
+ expect_no_more_invalidating_notifications!(:needs)
67
102
 
68
103
  @wc.use_instance_variables_for_assigns false
69
- expect_notification(:what => :needs, :why => :use_instance_variables_for_assigns_changed)
70
- expect_no_more_notifications!(:needs)
104
+ expect_invalidating_notification(:what => :needs, :why => :use_instance_variables_for_assigns_changed)
105
+ expect_no_more_invalidating_notifications!(:needs)
106
+ end
107
+
108
+ it "should only rebuild needs when a widget is actually instantiated" do
109
+ expect_no_more_invalidating_notifications!(:needs)
110
+ expect_no_more_rebuild_notifications!(:needs)
111
+
112
+ @wc.new
113
+
114
+ expect_no_more_invalidating_notifications!(:needs)
115
+ expect_rebuild_notification(:what => :needs, :why => :invalid, :class => @wc, :originating_class => @wc)
116
+ expect_no_more_rebuild_notifications!(:needs)
117
+ end
118
+
119
+ it "should only rebuild needs when a widget is actually instantiated the first time" do
120
+ expect_no_more_invalidating_notifications!(:needs)
121
+ expect_no_more_rebuild_notifications!(:needs)
122
+
123
+ @wc.new
124
+
125
+ expect_no_more_invalidating_notifications!(:needs)
126
+ expect_rebuild_notification(:what => :needs, :why => :invalid, :class => @wc, :originating_class => @wc)
127
+ expect_no_more_rebuild_notifications!(:needs)
128
+
129
+ @wc.new
130
+ expect_no_more_invalidating_notifications!(:needs)
131
+ expect_no_more_rebuild_notifications!(:needs)
132
+ end
133
+
134
+ it "should invalidate multiple times, but not rebuild more than once if multiple things are changed" do
135
+ @wc.new
136
+
137
+ expect_no_more_invalidating_notifications!(:needs)
138
+ expect_rebuild_notification(:what => :needs, :why => :invalid, :class => @wc, :originating_class => @wc)
139
+ expect_no_more_rebuild_notifications!(:needs)
140
+
141
+ @wc.needs :foobar
142
+ @wc.use_instance_variables_for_assigns true
143
+
144
+ expect_invalidating_notification(:what => :needs, :why => :need_declared, :class => @wc, :originating_class => @wc)
145
+ expect_invalidating_notification(:what => :needs, :why => :use_instance_variables_for_assigns_changed, :class => @wc, :originating_class => @wc)
146
+ expect_no_more_invalidating_notifications!(:needs)
147
+ end
148
+
149
+ it "should rebuild on both parent and child classes when a parent class is modified" do
150
+ wc_child = widget_class(:superclass => @wc)
151
+
152
+ expect_no_more_invalidating_notifications!(:needs)
153
+ expect_no_more_rebuild_notifications!(:needs)
154
+
155
+ @wc.needs :foobar
156
+
157
+ expect_invalidating_notification(:what => :needs, :why => :need_declared, :class => @wc, :originating_class => @wc)
158
+ expect_invalidating_notification(:what => :needs, :why => :need_declared, :class => wc_child, :originating_class => @wc)
159
+ expect_no_more_invalidating_notifications!(:needs)
160
+ expect_no_more_rebuild_notifications!(:needs)
161
+
162
+ wc_child.new(:foobar => 12)
163
+
164
+ expect_rebuild_notification(:what => :needs, :why => :invalid, :class => @wc, :originating_class => wc_child)
165
+ expect_rebuild_notification(:what => :needs, :why => :invalid, :class => wc_child, :originating_class => wc_child)
166
+ expect_no_more_rebuild_notifications!(:needs)
167
+ expect_no_more_invalidating_notifications!(:needs)
71
168
  end
72
169
  end
73
170
 
74
171
  describe "run_content" do
75
172
  it "should fire a notification when rebuilding because an around_content filter was added" do
76
173
  @wc.around_content :around1
77
- expect_notification(:what => :run_content, :why => :around_content_added)
78
- expect_no_more_notifications!(:run_content)
174
+ expect_rebuild_notification(:what => :run_content, :why => :around_content_added)
175
+ expect_no_more_rebuild_notifications!(:run_content)
79
176
 
80
177
  @wc.around_content :around2
81
- expect_notification(:what => :run_content, :why => :around_content_added)
82
- expect_no_more_notifications!(:run_content)
178
+ expect_rebuild_notification(:what => :run_content, :why => :around_content_added)
179
+ expect_no_more_rebuild_notifications!(:run_content)
83
180
  end
84
181
 
85
182
  it "should fire a notification when rebuilding because an around_content filter was removed" do
86
183
  @wc.around_content :around1
87
- expect_notification(:what => :run_content, :why => :around_content_added)
88
- expect_no_more_notifications!(:run_content)
184
+ expect_rebuild_notification(:what => :run_content, :why => :around_content_added)
185
+ expect_no_more_rebuild_notifications!(:run_content)
89
186
 
90
187
  @wc.remove_around_content :around1
91
- expect_notification(:what => :run_content, :why => :around_content_removed)
92
- expect_no_more_notifications!(:run_content)
188
+ expect_rebuild_notification(:what => :run_content, :why => :around_content_removed)
189
+ expect_no_more_rebuild_notifications!(:run_content)
93
190
  end
94
191
 
95
- it "should fire a notification when rebuilding because a localized content method was added" do
192
+ it "should fire a notification when rebuilding because use_localized_content_methods was changed" do
96
193
  @wc.class_eval do
97
- def localized_content_en
98
- text "foo"
99
- end
194
+ use_localized_content_methods true
100
195
  end
101
- expect_notification(:what => :run_content, :why => :localized_methods_presence_changed)
102
- expect_no_more_notifications!(:run_content)
196
+ expect_rebuild_notification(:what => :run_content, :why => :use_localized_content_methods_changed)
197
+ expect_no_more_rebuild_notifications!(:run_content)
103
198
 
104
- @wc.send(:remove_method, :localized_content_en)
105
- expect_notification(:what => :run_content, :why => :localized_methods_presence_changed)
106
- expect_no_more_notifications!(:run_content)
199
+ @wc.send(:use_localized_content_methods, false)
200
+ expect_rebuild_notification(:what => :run_content, :why => :use_localized_content_methods_changed)
201
+ expect_no_more_rebuild_notifications!(:run_content)
107
202
  end
108
203
  end
109
204
 
110
205
  describe "tag_methods" do
111
206
  it "should fire a notification when rebuilding because a tag was added" do
112
207
  @wc.tag :foo
113
- expect_notification(:what => :tag_methods, :why => :tags_declared)
114
- expect_no_more_notifications!(:tag_methods)
208
+ expect_rebuild_notification(:what => :tag_methods, :why => :tags_declared)
209
+ expect_no_more_rebuild_notifications!(:tag_methods)
115
210
  end
116
211
 
117
212
  it "should fire a notification when rebuilding because format_output has changed" do
118
213
  @wc.format_output true
119
- expect_notification(:what => :tag_methods, :why => :format_output_changed)
120
- expect_no_more_notifications!(:tag_methods)
214
+ expect_rebuild_notification(:what => :tag_methods, :why => :format_output_changed)
215
+ expect_no_more_rebuild_notifications!(:tag_methods)
121
216
 
122
217
  @wc.format_output false
123
- expect_notification(:what => :tag_methods, :why => :format_output_changed)
124
- expect_no_more_notifications!(:tag_methods)
218
+ expect_rebuild_notification(:what => :tag_methods, :why => :format_output_changed)
219
+ expect_no_more_rebuild_notifications!(:tag_methods)
125
220
  end
126
221
 
127
222
  it "should fire a notification when rebuilding because enforce_element_nesting_rules has changed" do
128
223
  @wc.enforce_element_nesting_rules true
129
- expect_notification(:what => :tag_methods, :why => :enforce_element_nesting_rules_changed)
130
- expect_no_more_notifications!(:tag_methods)
224
+ expect_rebuild_notification(:what => :tag_methods, :why => :enforce_element_nesting_rules_changed)
225
+ expect_no_more_rebuild_notifications!(:tag_methods)
131
226
 
132
227
  @wc.enforce_element_nesting_rules false
133
- expect_notification(:what => :tag_methods, :why => :enforce_element_nesting_rules_changed)
134
- expect_no_more_notifications!(:tag_methods)
228
+ expect_rebuild_notification(:what => :tag_methods, :why => :enforce_element_nesting_rules_changed)
229
+ expect_no_more_rebuild_notifications!(:tag_methods)
135
230
  end
136
231
 
137
232
  it "should fire a notification when rebuilding because enforce_attribute_rules has changed" do
138
233
  @wc.enforce_attribute_rules true
139
- expect_notification(:what => :tag_methods, :why => :enforce_attribute_rules_changed)
140
- expect_no_more_notifications!(:tag_methods)
234
+ expect_rebuild_notification(:what => :tag_methods, :why => :enforce_attribute_rules_changed)
235
+ expect_no_more_rebuild_notifications!(:tag_methods)
141
236
 
142
237
  @wc.enforce_attribute_rules false
143
- expect_notification(:what => :tag_methods, :why => :enforce_attribute_rules_changed)
144
- expect_no_more_notifications!(:tag_methods)
238
+ expect_rebuild_notification(:what => :tag_methods, :why => :enforce_attribute_rules_changed)
239
+ expect_no_more_rebuild_notifications!(:tag_methods)
145
240
  end
146
241
 
147
242
  it "should fire a notification when rebuilding because enforce_id_uniqueness has changed" do
148
243
  @wc.enforce_id_uniqueness true
149
- expect_notification(:what => :tag_methods, :why => :enforce_id_uniqueness_changed)
150
- expect_no_more_notifications!(:tag_methods)
244
+ expect_rebuild_notification(:what => :tag_methods, :why => :enforce_id_uniqueness_changed)
245
+ expect_no_more_rebuild_notifications!(:tag_methods)
151
246
 
152
247
  @wc.enforce_id_uniqueness false
153
- expect_notification(:what => :tag_methods, :why => :enforce_id_uniqueness_changed)
154
- expect_no_more_notifications!(:tag_methods)
248
+ expect_rebuild_notification(:what => :tag_methods, :why => :enforce_id_uniqueness_changed)
249
+ expect_no_more_rebuild_notifications!(:tag_methods)
155
250
  end
156
251
  end
157
252
 
@@ -163,46 +258,46 @@ describe "Fortitude rebuilding notifications", :type => :system do
163
258
 
164
259
  it "should fire with the right class for text methods" do
165
260
  @wc_subclass.format_output true
166
- expect_notification(:what => :text_methods, :why => :format_output_changed, :class => @wc_subclass, :originating_class => @wc_subclass)
167
- expect_no_more_notifications!(:text_methods)
261
+ expect_rebuild_notification(:what => :text_methods, :why => :format_output_changed, :class => @wc_subclass, :originating_class => @wc_subclass)
262
+ expect_no_more_rebuild_notifications!(:text_methods)
168
263
 
169
264
  @wc.format_output true
170
- expect_notification(:what => :text_methods, :why => :format_output_changed, :class => @wc, :originating_class => @wc)
171
- expect_notification(:what => :text_methods, :why => :format_output_changed, :class => @wc_subclass, :originating_class => @wc)
172
- expect_no_more_notifications!(:text_methods)
265
+ expect_rebuild_notification(:what => :text_methods, :why => :format_output_changed, :class => @wc, :originating_class => @wc)
266
+ expect_rebuild_notification(:what => :text_methods, :why => :format_output_changed, :class => @wc_subclass, :originating_class => @wc)
267
+ expect_no_more_rebuild_notifications!(:text_methods)
173
268
  end
174
269
 
175
270
  it "should fire with the right class for needs" do
176
271
  @wc_subclass.extra_assigns :use
177
- expect_notification(:what => :needs, :why => :extra_assigns_changed, :class => @wc_subclass, :originating_class => @wc_subclass)
178
- expect_no_more_notifications!(:needs)
272
+ expect_invalidating_notification(:what => :needs, :why => :extra_assigns_changed, :class => @wc_subclass, :originating_class => @wc_subclass)
273
+ expect_no_more_invalidating_notifications!(:needs)
179
274
 
180
275
  @wc.extra_assigns :error
181
- expect_notification(:what => :needs, :why => :extra_assigns_changed, :class => @wc, :originating_class => @wc)
182
- expect_notification(:what => :needs, :why => :extra_assigns_changed, :class => @wc_subclass, :originating_class => @wc)
183
- expect_no_more_notifications!(:needs)
276
+ expect_invalidating_notification(:what => :needs, :why => :extra_assigns_changed, :class => @wc, :originating_class => @wc)
277
+ expect_invalidating_notification(:what => :needs, :why => :extra_assigns_changed, :class => @wc_subclass, :originating_class => @wc)
278
+ expect_no_more_invalidating_notifications!(:needs)
184
279
  end
185
280
 
186
281
  it "should fire with the right class for run_content" do
187
282
  @wc_subclass.around_content :around1
188
- expect_notification(:what => :run_content, :why => :around_content_added, :class => @wc_subclass, :originating_class => @wc_subclass)
189
- expect_no_more_notifications!(:run_content)
283
+ expect_rebuild_notification(:what => :run_content, :why => :around_content_added, :class => @wc_subclass, :originating_class => @wc_subclass)
284
+ expect_no_more_rebuild_notifications!(:run_content)
190
285
 
191
286
  @wc.around_content :around2
192
- expect_notification(:what => :run_content, :why => :around_content_added, :class => @wc, :originating_class => @wc)
193
- expect_notification(:what => :run_content, :why => :around_content_added, :class => @wc_subclass, :originating_class => @wc)
194
- expect_no_more_notifications!(:run_content)
287
+ expect_rebuild_notification(:what => :run_content, :why => :around_content_added, :class => @wc, :originating_class => @wc)
288
+ expect_rebuild_notification(:what => :run_content, :why => :around_content_added, :class => @wc_subclass, :originating_class => @wc)
289
+ expect_no_more_rebuild_notifications!(:run_content)
195
290
  end
196
291
 
197
292
  it "should fire with the right class for tag_methods" do
198
293
  @wc_subclass.format_output true
199
- expect_notification(:what => :tag_methods, :why => :format_output_changed, :class => @wc_subclass, :originating_class => @wc_subclass)
200
- expect_no_more_notifications!(:tag_methods)
294
+ expect_rebuild_notification(:what => :tag_methods, :why => :format_output_changed, :class => @wc_subclass, :originating_class => @wc_subclass)
295
+ expect_no_more_rebuild_notifications!(:tag_methods)
201
296
 
202
297
  @wc.format_output true
203
- expect_notification(:what => :tag_methods, :why => :format_output_changed, :class => @wc, :originating_class => @wc)
204
- expect_notification(:what => :tag_methods, :why => :format_output_changed, :class => @wc_subclass, :originating_class => @wc)
205
- expect_no_more_notifications!(:tag_methods)
298
+ expect_rebuild_notification(:what => :tag_methods, :why => :format_output_changed, :class => @wc, :originating_class => @wc)
299
+ expect_rebuild_notification(:what => :tag_methods, :why => :format_output_changed, :class => @wc_subclass, :originating_class => @wc)
300
+ expect_no_more_rebuild_notifications!(:tag_methods)
206
301
  end
207
302
  end
208
303
  end