erector 0.5.1 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. data/README.txt +6 -5
  2. data/VERSION.yml +5 -0
  3. data/bin/{erect → erector} +0 -0
  4. data/lib/erector.rb +3 -1
  5. data/lib/erector/erect.rb +1 -1
  6. data/lib/erector/erected.rb +1 -1
  7. data/lib/erector/rails.rb +2 -1
  8. data/lib/erector/rails/extensions/action_controller.rb +25 -7
  9. data/lib/erector/rails/extensions/rails_widget.rb +38 -0
  10. data/lib/erector/rails/extensions/{widget.rb → rails_widget/helpers.rb} +2 -9
  11. data/lib/erector/rails/rails_version.rb +6 -0
  12. data/lib/erector/rails/template_handlers/action_view_template_handler.rb +43 -11
  13. data/lib/erector/version.rb +4 -2
  14. data/lib/erector/widget.rb +221 -74
  15. data/lib/erector/widgets/table.rb +34 -8
  16. data/spec/erector/indentation_spec.rb +39 -24
  17. data/spec/erector/widget_spec.rb +197 -64
  18. data/spec/erector/widgets/table_spec.rb +3 -3
  19. data/spec/spec.opts +1 -0
  20. data/spec/spec_helper.rb +2 -4
  21. data/spec/spec_suite.rb +6 -12
  22. metadata +24 -70
  23. data/lib/erector/rails/extensions/action_controller/1.2.5/action_controller.rb +0 -17
  24. data/lib/erector/rails/extensions/action_controller/2.2.0/action_controller.rb +0 -26
  25. data/lib/erector/rails/extensions/widget/1.2.5/widget.rb +0 -18
  26. data/lib/erector/rails/extensions/widget/2.2.0/widget.rb +0 -23
  27. data/lib/erector/rails/supported_rails_versions.rb +0 -13
  28. data/lib/erector/rails/template_handlers/1.2.5/action_view_template_handler.rb +0 -32
  29. data/lib/erector/rails/template_handlers/2.0.0/action_view_template_handler.rb +0 -36
  30. data/lib/erector/rails/template_handlers/2.1.0/action_view_template_handler.rb +0 -31
  31. data/lib/erector/rails/template_handlers/2.2.0/action_view_template_handler.rb +0 -46
  32. data/spec/erect/erect_spec.rb +0 -145
  33. data/spec/erect/erected_spec.rb +0 -80
  34. data/spec/erect/rhtml_parser_spec.rb +0 -318
@@ -1,24 +1,49 @@
1
1
  module Erector
2
2
  module Widgets #:nodoc:
3
+ # The Table widget provides the ability to render a table from a
4
+ # list of objects (one for each row).
5
+ #
6
+ # Because the default for the column titles utilizes the ActiveSupport
7
+ # Inflector#titleize method, this widget requires active_support to be loaded.
8
+ #
9
+ # class UsersTable < Erector::Widgets::Table
10
+ # column :first_name
11
+ # column :last_name
12
+ # column :email
13
+ # row_classes :even, :odd
14
+ # end
15
+ #
16
+ # widget UsersTable, :row_objects => [user_1, user_2, user_3]
3
17
  class Table < Erector::Widget
4
18
  ColumnDefinition = Struct.new(:id, :name, :cell_proc)
5
19
  class << self
6
- def column(id, name=id.to_s.humanize.titleize, &cell_proc)
20
+ # Define a column, optionally specifying the name (the heading
21
+ # that the user sees) and a block which renders the cell given
22
+ # a row object. If the block is not specified, the cell contains
23
+ # the result of calling a method whose name is id.
24
+ #
25
+ # The name can be a string or a proc.
26
+ def column(id, name=id.to_s.titleize, &cell_proc)
7
27
  cell_proc ||= proc {|object| text object.__send__(id)}
8
28
  column_definitions << ColumnDefinition.new(id, name, cell_proc)
9
29
  end
10
30
 
11
- def column_definitions
31
+ def column_definitions #:nodoc:
12
32
  @column_definitions ||= []
13
33
  end
14
34
 
35
+ # A list of HTML classes to apply to the rows in turn. After the
36
+ # list is exhausted, start again at the start. The most
37
+ # common use for this is to specify one class for odd rows
38
+ # and a different class for even rows.
15
39
  def row_classes(*row_classes)
16
40
  @row_class_list = row_classes
17
41
  end
18
42
  attr_reader :row_class_list
19
43
  end
20
44
 
21
- def render
45
+ # The standard erector content method.
46
+ def content
22
47
  table do
23
48
  thead do
24
49
  tr do
@@ -42,7 +67,7 @@ module Erector
42
67
  end
43
68
 
44
69
  protected
45
- def row(object, index)
70
+ def row(object, index) #:nodoc:
46
71
  tr(:class => row_css_class(object, index)) do
47
72
  column_definitions.each do |column_def|
48
73
  td do
@@ -52,19 +77,20 @@ module Erector
52
77
  end
53
78
  end
54
79
 
55
- # Im overridable
80
+ # You can override this method to provide a class for a row
81
+ # (as an alternative to calling row_classes).
56
82
  def row_css_class(object, index)
57
83
  cycle(index)
58
84
  end
59
85
 
60
- def column_definitions
86
+ def column_definitions #:nodoc:
61
87
  self.class.column_definitions
62
88
  end
63
89
 
64
- def cycle(index)
90
+ def cycle(index) #:nodoc:
65
91
  list = self.class.row_class_list
66
92
  list ? list[index % list.length] : ''
67
93
  end
68
94
  end
69
95
  end
70
- end
96
+ end
@@ -4,8 +4,9 @@ describe "indentation" do
4
4
 
5
5
  it "can detect newliney tags" do
6
6
  widget = ::Erector::Widget.new
7
- string = widget.output
8
- widget.enable_prettyprint = true
7
+ widget.instance_eval do
8
+ @prettyprint = true
9
+ end
9
10
  widget.newliney("i").should == false
10
11
  widget.newliney("table").should == true
11
12
  end
@@ -14,21 +15,21 @@ describe "indentation" do
14
15
  Erector::Widget.new() do
15
16
  text "Hello, "
16
17
  b "World"
17
- end.enable_prettyprint(true).to_s.should == "Hello, <b>World</b>"
18
+ end.to_pretty.should == "Hello, <b>World</b>"
18
19
  end
19
20
 
20
21
  it "should add newlines before open newliney tags" do
21
22
  Erector::Widget.new() do
22
23
  p "foo"
23
24
  p "bar"
24
- end.enable_prettyprint(true).to_s.should == "<p>foo</p>\n<p>bar</p>\n"
25
+ end.to_pretty.should == "<p>foo</p>\n<p>bar</p>\n"
25
26
  end
26
27
 
27
28
  it "should add newlines between text and open newliney tag" do
28
29
  Erector::Widget.new() do
29
30
  text "One"
30
31
  p "Two"
31
- end.enable_prettyprint(true).to_s.should == "One\n<p>Two</p>\n"
32
+ end.to_pretty.should == "One\n<p>Two</p>\n"
32
33
  end
33
34
 
34
35
  it "should add newlines after end newliney tags" do
@@ -36,7 +37,7 @@ describe "indentation" do
36
37
  tr do
37
38
  td "cell"
38
39
  end
39
- end.enable_prettyprint(true).to_s.should == "<tr>\n <td>cell</td>\n</tr>\n"
40
+ end.to_pretty.should == "<tr>\n <td>cell</td>\n</tr>\n"
40
41
  end
41
42
 
42
43
  it "should treat empty elements as start and end" do
@@ -44,7 +45,7 @@ describe "indentation" do
44
45
  p "before"
45
46
  br
46
47
  p "after"
47
- end.enable_prettyprint(true).to_s.should == "<p>before</p>\n<br />\n<p>after</p>\n"
48
+ end.to_pretty.should == "<p>before</p>\n<br />\n<p>after</p>\n"
48
49
  end
49
50
 
50
51
  it "empty elements sets at_start_of_line" do
@@ -52,7 +53,7 @@ describe "indentation" do
52
53
  text "before"
53
54
  br
54
55
  p "after"
55
- end.enable_prettyprint(true).to_s.should == "before\n<br />\n<p>after</p>\n"
56
+ end.to_pretty.should == "before\n<br />\n<p>after</p>\n"
56
57
  end
57
58
 
58
59
  it "will not insert extra space before/after input element" do
@@ -62,7 +63,7 @@ describe "indentation" do
62
63
  text 'Name'
63
64
  input :type => 'text'
64
65
  text 'after'
65
- end.enable_prettyprint(true).to_s.should == 'Name<input type="text" />after'
66
+ end.to_pretty.should == 'Name<input type="text" />after'
66
67
  end
67
68
 
68
69
  it "will indent" do
@@ -77,7 +78,7 @@ describe "indentation" do
77
78
  end
78
79
  end
79
80
  end
80
- end.enable_prettyprint(true).to_s.should == <<END
81
+ end.to_pretty.should == <<END
81
82
  <html>
82
83
  <head>
83
84
  <title>hi</title>
@@ -91,22 +92,43 @@ describe "indentation" do
91
92
  END
92
93
  end
93
94
 
95
+ it "preserves indentation for sub-rendered widgets" do
96
+ tea = Erector::Widget.new do
97
+ div do
98
+ p "oolong"
99
+ end
100
+ end
101
+ cup = Erector::Widget.new do
102
+ div do
103
+ p "fine china"
104
+ tea.write_via(self)
105
+ end
106
+ end
107
+
108
+ cup.to_pretty.should == <<END
109
+ <div>
110
+ <p>fine china</p>
111
+ <div>
112
+ <p>oolong</p>
113
+ </div>
114
+ </div>
115
+ END
116
+ end
117
+
94
118
  it "can turn off newlines" do
95
119
  Erector::Widget.new() do
96
120
  text "One"
97
121
  p "Two"
98
- end.enable_prettyprint(false).to_s.should == "One<p>Two</p>"
122
+ end.to_s.should == "One<p>Two</p>"
99
123
  end
100
124
 
101
- it "cannot turn newlines on and off, because the output is cached" do
125
+ it "can turn newlines on and off" do
102
126
  widget = Erector::Widget.new() do
103
127
  text "One"
104
128
  p "Two"
105
- end.enable_prettyprint(false)
106
- widget.to_s.should == "One<p>Two</p>"
107
- widget.enable_prettyprint(true)
129
+ end
108
130
  widget.to_s.should == "One<p>Two</p>"
109
- widget.enable_prettyprint(false)
131
+ widget.to_pretty.should == "One\n<p>Two</p>\n"
110
132
  widget.to_s.should == "One<p>Two</p>"
111
133
  end
112
134
 
@@ -114,14 +136,7 @@ END
114
136
  widget = Erector::Widget.new() do
115
137
  text "One"
116
138
  p "Two"
117
- end.enable_prettyprint(false).to_pretty.should == "One\n<p>Two</p>\n"
118
- end
119
-
120
- it "to_pretty will leave newlines on if they already were" do
121
- widget = Erector::Widget.new() do
122
- text "One"
123
- p "Two"
124
- end.enable_prettyprint(true).to_pretty.should == "One\n<p>Two</p>\n"
139
+ end.to_pretty.should == "One\n<p>Two</p>\n"
125
140
  end
126
141
 
127
142
  it "can turn newlines on/off via global variable" do
@@ -11,42 +11,42 @@ module WidgetSpec
11
11
 
12
12
  describe "#to_s" do
13
13
  class << self
14
- define_method("invokes #render and returns the string representation of the rendered widget") do
15
- it "invokes #render and returns the string representation of the rendered widget" do
14
+ define_method("invokes #content and returns the string representation of the rendered widget") do
15
+ it "invokes #content and returns the string representation of the rendered widget" do
16
16
  widget = Erector::Widget.new do
17
17
  div "Hello"
18
18
  end
19
- mock.proxy(widget).render
19
+ mock.proxy(widget).content
20
20
  widget.to_s.should == "<div>Hello</div>"
21
21
  end
22
22
  end
23
23
  end
24
24
 
25
25
  context "when passed no arguments" do
26
- send "invokes #render and returns the string representation of the rendered widget"
26
+ send "invokes #content and returns the string representation of the rendered widget"
27
27
  end
28
28
 
29
- context "when passed an argument that is #render" do
30
- send "invokes #render and returns the string representation of the rendered widget"
29
+ context "when passed an argument that is #content" do
30
+ send "invokes #content and returns the string representation of the rendered widget"
31
31
  end
32
32
 
33
- context "when passed an argument that is not #render" do
33
+ context "when passed an argument that is not #content" do
34
34
  attr_reader :widget
35
35
  before do
36
36
  @widget = Erector::Widget.new
37
- def widget.alternate_render
38
- div "Hello from Alternate Render"
37
+ def widget.alternate_content
38
+ div "Hello from Alternate Write"
39
39
  end
40
- mock.proxy(widget).alternate_render
40
+ mock.proxy(widget).alternate_content
41
41
  end
42
42
 
43
43
  it "invokes the passed in method name and returns the string representation of the rendered widget" do
44
- widget.to_s(:alternate_render).should == "<div>Hello from Alternate Render</div>"
44
+ widget.to_s(:content_method_name => :alternate_content).should == "<div>Hello from Alternate Write</div>"
45
45
  end
46
46
 
47
- it "does not invoke #render" do
48
- dont_allow(widget).render
49
- widget.to_s(:alternate_render)
47
+ it "does not invoke #content" do
48
+ dont_allow(widget).content
49
+ widget.to_s(:content_method_name => :alternate_content)
50
50
  end
51
51
  end
52
52
  end
@@ -60,18 +60,76 @@ module WidgetSpec
60
60
  end
61
61
  end
62
62
 
63
+ describe '#widget' do
64
+ context "basic nesting" do
65
+ before do
66
+ class Parent < Erector::Widget
67
+ def content
68
+ text 1
69
+ widget Child do
70
+ text 2
71
+ third
72
+ end
73
+ end
74
+
75
+ def third
76
+ text 3
77
+ end
78
+ end
79
+
80
+ class Child < Erector::Widget
81
+ def content
82
+ super
83
+ end
84
+ end
85
+ end
86
+
87
+ it "renders nested widgets in the correct order" do
88
+ Parent.new.to_s.should == '123'
89
+ end
90
+ end
91
+
92
+ end
93
+
63
94
  describe "#widget" do
95
+ class Orphan < Erector::Widget
96
+ def content
97
+ p @name
98
+ end
99
+ end
100
+
101
+ context "when passed a class" do
102
+ it "renders it" do
103
+ Erector::Widget.new do
104
+ div do
105
+ widget Orphan, :name => "Annie"
106
+ end
107
+ end.to_s.should == "<div><p>Annie</p></div>"
108
+ end
109
+ end
110
+
111
+ context "when passed an instance" do
112
+ it "renders it" do
113
+ Erector::Widget.new do
114
+ div do
115
+ widget Orphan.new(:name => "Oliver")
116
+ end
117
+ end.to_s.should == "<div><p>Oliver</p></div>"
118
+ end
119
+ end
120
+
64
121
  context "when nested" do
65
122
  it "renders the tag around the rest of the block" do
66
123
  parent_widget = Class.new(Erector::Widget) do
67
- def render
124
+ def content
68
125
  div :id => "parent_widget" do
69
126
  super
70
127
  end
71
128
  end
72
129
  end
130
+
73
131
  child_widget = Class.new(Erector::Widget) do
74
- def render
132
+ def content
75
133
  div :id => "child_widget" do
76
134
  super
77
135
  end
@@ -79,7 +137,8 @@ module WidgetSpec
79
137
  end
80
138
 
81
139
  widget = Class.new(Erector::Widget) do
82
- def render
140
+ needs :parent_widget, :child_widget
141
+ def content
83
142
  widget(parent_widget) do
84
143
  widget(child_widget) do
85
144
  super
@@ -88,7 +147,7 @@ module WidgetSpec
88
147
  end
89
148
  end
90
149
 
91
- widget.new(nil, :parent_widget => parent_widget, :child_widget => child_widget) do
150
+ widget.new(:parent_widget => parent_widget, :child_widget => child_widget) do
92
151
  div :id => "widget"
93
152
  end.to_s.should == '<div id="parent_widget"><div id="child_widget"><div id="widget"></div></div></div>'
94
153
  end
@@ -583,65 +642,23 @@ module WidgetSpec
583
642
  end
584
643
  end
585
644
 
586
- describe '#widget' do
587
- before do
588
- class Parent < Erector::Widget
589
- def render
590
- text 1
591
- widget Child do
592
- text 2
593
- third
594
- end
595
- end
596
-
597
- def third
598
- text 3
599
- end
600
- end
601
-
602
- class Child < Erector::Widget
603
- def render
604
- super
605
- end
606
- end
607
- end
608
-
609
- it "renders nested widgets in the correct order" do
610
- Parent.new.to_s.should == '123'
611
- end
612
- end
613
-
614
- describe '#render_to' do
645
+ describe '#write_via' do
615
646
  class A < Erector::Widget
616
- def render
647
+ def content
617
648
  p "A"
618
649
  end
619
650
  end
620
651
 
621
- it "renders to a doc" do
622
- class B < Erector::Widget
623
- def render
624
- text "B"
625
- A.new.render_to(@output)
626
- text "B"
627
- end
628
- end
629
- b = B.new
630
- b.to_s.should == "B<p>A</p>B"
631
- b.output.size.should == 10 # B, <p>, A, </p>, B
632
- end
633
-
634
652
  it "renders to a widget's doc" do
635
653
  class B < Erector::Widget
636
- def render
654
+ def content
637
655
  text "B"
638
- A.new.render_to(self)
656
+ A.new.write_via(self)
639
657
  text "B"
640
658
  end
641
659
  end
642
660
  b = B.new
643
661
  b.to_s.should == "B<p>A</p>B"
644
- b.output.size.should == 10 # B, <p>, A, </p>, B
645
662
  end
646
663
 
647
664
  it "passing a widget to text method renders it" do
@@ -653,5 +670,121 @@ module WidgetSpec
653
670
  end
654
671
 
655
672
  end
673
+
674
+ describe "when declaring parameters with the 'needs' macro" do
675
+ it "doesn't complain if there aren't any needs declared" do
676
+ class Thing1 < Erector::Widget
677
+ end
678
+ Thing1.new
679
+ end
680
+
681
+ it "allows you to say that you don't want any parameters" do
682
+ class Thing2 < Erector::Widget
683
+ needs nil
684
+ end
685
+ lambda { Thing2.new }.should_not raise_error
686
+ lambda { Thing2.new(:foo => 1) }.should raise_error
687
+ end
688
+
689
+ it "doesn't complain if you pass it a declared parameter" do
690
+ class Thing2b < Erector::Widget
691
+ needs :foo
692
+ end
693
+ lambda { Thing2b.new(:foo => 1) }.should_not raise_error
694
+ end
695
+
696
+ it "complains if you pass it an undeclared parameter" do
697
+ class Thing3 < Erector::Widget
698
+ needs :foo
699
+ end
700
+ lambda { Thing3.new(:bar => 1) }.should raise_error
701
+ end
702
+
703
+ it "allows multiple declared parameters" do
704
+ class Thing4 < Erector::Widget
705
+ needs :foo, :bar
706
+ end
707
+ lambda { Thing4.new(:foo => 1, :bar => 2) }.should_not raise_error
708
+ end
709
+
710
+ it "complains when passing in an extra parameter after declaring many parameters" do
711
+ class Thing5 < Erector::Widget
712
+ needs :foo, :bar
713
+ end
714
+ lambda { Thing5.new(:foo => 1, :bar => 2, :baz => 3) }.should raise_error
715
+ end
716
+
717
+ it "complains when you forget to pass in a needed parameter" do
718
+ class Thing6 < Erector::Widget
719
+ needs :foo, :bar
720
+ end
721
+ lambda { Thing6.new(:foo => 1) }.should raise_error
722
+ end
723
+
724
+ it "doesn't complain if you omit a parameter with a default value" do
725
+ class Thing7 < Erector::Widget
726
+ needs :foo
727
+ needs :bar => 7
728
+ needs :baz => 8
729
+ end
730
+ lambda {
731
+ thing = Thing7.new(:foo => 1, :baz => 3)
732
+ thing.bar.should equal(7)
733
+ thing.baz.should equal(3)
734
+ }.should_not raise_error
735
+ end
736
+
737
+ it "allows multiple values on a line, including default values at the end of the line" do
738
+ class Thing8 < Erector::Widget
739
+ needs :foo, :bar => 7, :baz => 8
740
+ end
741
+ lambda {
742
+ thing = Thing8.new(:foo => 1, :baz => 2)
743
+ thing.foo.should equal(1)
744
+ thing.bar.should equal(7)
745
+ thing.baz.should equal(2)
746
+ }.should_not raise_error
747
+ end
748
+
749
+ it "allows nil to be a default value" do
750
+ class Thing9 < Erector::Widget
751
+ needs :foo => nil
752
+ end
753
+ lambda {
754
+ thing = Thing9.new
755
+ thing.foo.should be_nil
756
+ }.should_not raise_error
757
+ end
758
+
759
+ it "accumulates needs across the inheritance chain" do
760
+ class Vehicle < Erector::Widget
761
+ needs :wheels
762
+ end
763
+
764
+ class Car < Vehicle
765
+ needs :engine
766
+ end
767
+
768
+ lambda { Car.new(:engine => 'V-8', :wheels => 4) }.should_not raise_error
769
+ lambda { Car.new(:engine => 'V-8') }.should raise_error
770
+ lambda { Car.new(:wheels => 4) }.should raise_error
771
+ end
772
+
773
+ it "defines accessors for each of the needed variables" do
774
+ class NeedfulThing < Erector::Widget
775
+ needs :love
776
+ end
777
+ thing = NeedfulThing.new(:love => "all we need")
778
+ thing.love.should == "all we need"
779
+ end
780
+
781
+ it "doesnt define accessors for non-needed variables" do
782
+ class NeedlessThing < Erector::Widget
783
+ end
784
+ thing = NeedlessThing.new(:love => "all we need")
785
+ lambda {thing.love}.should raise_error
786
+ end
787
+
788
+ end
656
789
  end
657
790
  end