erector 0.1.25 → 0.2.42

Sign up to get free protection for your applications and to get access to all the features.
data/README.txt CHANGED
@@ -6,20 +6,33 @@
6
6
 
7
7
  == DESCRIPTION
8
8
 
9
- Erector is a Builder-based view framework, inspired by Markaby but overcoming some of its flaws. In Erector all views are
10
- objects, not template files, which allows the full power of OO (inheritance, modular decomposition, encapsulation) in views.
9
+ Erector is a Builder-like view framework, inspired by Markaby but overcoming
10
+ some of its flaws. In Erector all views are objects, not template files,
11
+ which allows the full power of object-oriented programming (inheritance,
12
+ modular decomposition, encapsulation) in views.
11
13
 
12
14
  == FEATURES/PROBLEMS:
13
15
 
14
- This is a *prerelease work in progress* and this gem is **NOT READY FOR USE** by anyone who's not on the Erector team yet. We'll be rolling out a
15
- version 0.2.0 soon which should include howto documentation and such.
16
+ While Erector is in use on several projects, it is still at a relatively
17
+ early stage. In particular, not all features are documented (although
18
+ the most important ones are).
16
19
 
17
20
  == SYNOPSIS
18
21
 
19
- TODO (HOWTO, sample code, etc.)
22
+ require 'erector'
23
+
24
+ class Hello < Erector::Widget
25
+ def render
26
+ div do
27
+ text "Hello!"
28
+ end
29
+ end
30
+ end
20
31
 
21
32
  == REQUIREMENTS
22
33
 
34
+ The gem depends on hoe and rake, although this is just for building
35
+ erector (those who just use erector won't need these).
23
36
 
24
37
  == INSTALL
25
38
 
@@ -27,9 +40,14 @@ To install as a gem:
27
40
 
28
41
  * sudo gem install erector
29
42
 
30
- To install as a plugin:
43
+ Then add "require 'erector'" to any files which need erector.
44
+
45
+ To install as a Rails plugin:
31
46
 
32
- * TODO
47
+ * Copy the erector source to vendor/plugins/erector in your Rails directory.
48
+
49
+ When installing this way, erector is automatically available to your Rails code
50
+ (no require directive is needed).
33
51
 
34
52
  == LICENSE:
35
53
 
@@ -56,19 +74,29 @@ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
56
74
  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
57
75
  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
58
76
 
59
- == USER DOCUMENTATION
77
+ == MOTIVATION
60
78
 
61
- TODO (more on how you get started, and call it from rails)
79
+ Why use Erector? This section will soon become a real essay or blog post,
80
+ but briefly:
62
81
 
63
- The basic way to construct some HTML/XML with erector is to pass a
64
- block to Erector::Widget.new. For example:
82
+ * Markaby-style DOM Domain language
83
+ * Your views are real classes, written in a real language, allowing
84
+ * Functional decomposition
85
+ * Inheritance
86
+ * Composition, not partials
87
+ * Well-defined semantics for variables, loops, blocks
88
+ * Dependency injection via constructor params
89
+ * As little magic as possible (e.g. no automagic copying of "assigns" variable from your controller)
90
+ * yield works again (Markaby broke it)
91
+ * Very testable
92
+ * form_for ERB code is craaaaazy (not to mention the quagmire of options vs. htmloptions)
93
+ * Output is streamed, improving performance over string copy
65
94
 
66
- html = Erector::Widget.new do
67
- p "Hello, world!"
68
- end
69
- html.to_s #=> <p>Hello, world!</p>
70
95
 
71
- Or, subclass Erector::Widget and implement a render method:
96
+ == USER DOCUMENTATION
97
+
98
+ The basic way to construct some HTML/XML with erector is to
99
+ subclass Erector::Widget and implement a render method:
72
100
 
73
101
  class Hello < Erector::Widget
74
102
  def render
@@ -108,6 +136,39 @@ Here are the basics:
108
136
 
109
137
  TODO: document more obscure features like capture, Table, :class => ['one', 'two']
110
138
 
139
+ === Using erector from Ruby on Rails
140
+
141
+ Your views are just ruby classes. Your controller instantiates the
142
+ relevant view and calls render. For example:
143
+
144
+ app/controllers/welcome_controller.rb:
145
+
146
+ class WelcomeController < ApplicationController
147
+
148
+ def index
149
+ render :template => 'welcome/show'
150
+ end
151
+
152
+ end
153
+
154
+ app/views/welcome/show.rb:
155
+
156
+ class Views::Welcome::Show < Erector::Widget
157
+
158
+ def render
159
+ html do
160
+ head do
161
+ title "Welcome page"
162
+ end
163
+
164
+ body do
165
+ p "Hello, world"
166
+ end
167
+ end
168
+ end
169
+
170
+ end
171
+
111
172
  === Layout Inheritance
112
173
 
113
174
  Erector replaces the typical Rails layout mechanism with a more natural construct, the use of inheritance. Want a common
@@ -140,6 +201,16 @@ Here the abstract layout widget is used in a concrete fashion by the template-ba
140
201
  would be implemented by subclassing widgets, but the layout template sets it directly and then calls to_s on the layout widget.
141
202
  This allows the same layout to be shared in a backward compatible way.
142
203
 
204
+ === Other ways to call erector
205
+
206
+ Instead of subclassing Erector::Widget and implementing a render
207
+ method, you can pass a block to Erector::Widget.new. For example:
208
+
209
+ html = Erector::Widget.new do
210
+ p "Hello, world!"
211
+ end
212
+ html.to_s #=> <p>Hello, world!</p>
213
+
143
214
  == DEVELOPER NOTES
144
215
 
145
216
  * Check out project from rubyforge:
@@ -163,12 +234,13 @@ This allows the same layout to be shared in a backward compatible way.
163
234
 
164
235
  * Versions are of the form major.minor.tiny
165
236
  * Tiny revisions fix bugs or documentation
237
+ * Tiny revisions are roughly equal to the svn revision number when they were made
166
238
  * Minor revisions add API calls, or change behavior
167
239
  * Minor revisions may also remove API calls, but these must be clearly announced in History.txt, with instructions on how to migrate
168
240
  * Major revisions are about marketing more than technical needs. We will stay in major version 0 until we're happy taking the "alpha" label off it. And if we ever do a major overhaul of the API, especially one that breaks backwards compatibility, we will probably want to increment the major version.
169
- * We will not be shy about incrementing version numbers -- if we end up going to version 0.943.67 then so be it.
241
+ * We will not be shy about incrementing version numbers -- if we end up going to version 0.943.67454 then so be it.
170
242
  * Developers should attempt to add lines in History.txt to reflect their checkins. These should reflect feature-level changes, not just one line per checkin. The top section of History.txt is used as the Release Notes by the "rake publish" task and will appear on the RubyForge file page.
171
- * Someone making a release must fill in the version number in History.txt as well as in Rakefile. Note that "rake publish" requires a "VERSION=1.2.3" parameter to confirm you're releasing the version you intend.
243
+ * Someone making a release must fill in the version number in History.txt as well as in Rakefile. Note that "rake release" requires a "VERSION=1.2.3" parameter to confirm you're releasing the version you intend.
172
244
  * As soon as a release is made and published, the publisher should go into History.txt and make a new section. Since we won't yet know what the next version will be called, the new section will be noted by a single "==" at the top of the file.
173
245
 
174
246
 
data/lib/erector.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require "rubygems"
2
2
  require "action_controller"
3
3
  require "erector/extensions/action_controller"
4
+ require "erector/extensions/action_view_template_handler"
4
5
  require "erector/extensions/object"
5
6
  require "erector/helpers"
6
7
  require "erector/html_parts"
@@ -8,6 +8,15 @@ class ActionController::Base
8
8
  @rendered_widget = widget_class.new(@template, assigns.merge(:params => params))
9
9
  @rendered_widget.to_s
10
10
  end
11
+
12
+ def render_with_erector_widget(*options, &block)
13
+ if options.first.is_a?(Hash) && widget = options.first.delete(:widget)
14
+ render_widget widget, *options, &block
15
+ else
16
+ render_without_erector_widget *options, &block
17
+ end
18
+ end
19
+ alias_method_chain :render, :erector_widget
11
20
 
12
21
  attr_reader :rendered_widget
13
22
  end
@@ -0,0 +1,26 @@
1
+ module ActionView
2
+ module TemplateHandlers
3
+ class Erector
4
+ def initialize(view)
5
+ @view = view
6
+ end
7
+
8
+ def render(template, local_assigns)
9
+ paths = @view.first_render.split('/')
10
+ dot_rb = /\.rb$/
11
+ widget_class = paths.inject(Views) do |current_module, node|
12
+ current_module.const_get(node.gsub(dot_rb, '').camelize)
13
+ end
14
+
15
+ rendered_widget = widget_class.new(@view, @view.assigns)
16
+ rendered_widget.to_s
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ ActionView::Base.instance_eval do
23
+ if respond_to?(:register_template_handler)
24
+ register_template_handler :rb, ActionView::TemplateHandlers::Erector
25
+ end
26
+ end
@@ -39,7 +39,6 @@ module Erector
39
39
  end
40
40
  end
41
41
  @helpers = helpers
42
- fake_erbout
43
42
  @parent = block ? eval("self", block.binding) : nil
44
43
  @doc = doc
45
44
  @block = block
@@ -50,7 +49,7 @@ module Erector
50
49
  instance_eval(&@block)
51
50
  end
52
51
  end
53
-
52
+
54
53
  def render_to(doc)
55
54
  @doc = doc
56
55
  render
@@ -128,7 +127,7 @@ module Erector
128
127
  # (maybe, but the syntax is specific to javascript; it isn't
129
128
  # really a generic XML CDATA section. Specifically,
130
129
  # ]]> within value is not treated as ending the
131
- # CDATA section by Firefox2 when parsing text/html,
130
+ # CDATA section by Firefox2 when parsing text/html,
132
131
  # although I guess we could refuse to generate ]]>
133
132
  # there, for the benefit of XML/XHTML parsers).
134
133
  rawtext "\n// <![CDATA[\n"
@@ -226,14 +225,22 @@ module Erector
226
225
  super
227
226
  end
228
227
  end
229
-
230
- def fake_erbout
228
+
229
+ def fake_erbout(&blk)
231
230
  widget = self
232
231
  @helpers.metaclass.class_eval do
232
+ raise "Cannot nest fake_erbout" if instance_methods.include?('concat_without_erector')
233
+ alias_method :concat_without_erector, :concat
233
234
  define_method :concat do |some_text, binding|
234
235
  widget.text widget.raw(some_text)
235
236
  end
236
237
  end
238
+ yield
239
+ ensure
240
+ @helpers.metaclass.class_eval do
241
+ alias_method :concat, :concat_without_erector
242
+ remove_method :concat_without_erector
243
+ end
237
244
  end
238
245
  end
239
246
  end
@@ -20,32 +20,43 @@ module Erector
20
20
 
21
21
  def render
22
22
  table do
23
- tr do
24
- column_definitions.each do |column_def|
25
- th do
26
- if column_def.name.is_a?(Proc)
27
- self.instance_exec(column_def.id, &column_def.name)
28
- else
29
- text column_def.name
23
+ thead do
24
+ tr do
25
+ column_definitions.each do |column_def|
26
+ th do
27
+ if column_def.name.is_a?(Proc)
28
+ self.instance_exec(column_def.id, &column_def.name)
29
+ else
30
+ text column_def.name
31
+ end
30
32
  end
31
33
  end
32
34
  end
33
35
  end
34
36
  tbody do
35
37
  @row_objects.each_with_index do |object, index|
36
- tr(:class => cycle(index)) do
37
- column_definitions.each do |column_def|
38
- td do
39
- self.instance_exec(object, &column_def.cell_proc)
40
- end
41
- end
42
- end
38
+ row object, index
43
39
  end
44
40
  end
45
41
  end
46
42
  end
47
43
 
48
44
  protected
45
+ def row(object, index)
46
+ tr(:class => row_css_class(object, index)) do
47
+ column_definitions.each do |column_def|
48
+ td do
49
+ self.instance_exec(object, &column_def.cell_proc)
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ # Im overridable
56
+ def row_css_class(object, index)
57
+ cycle(index)
58
+ end
59
+
49
60
  def column_definitions
50
61
  self.class.column_definitions
51
62
  end
@@ -0,0 +1,7 @@
1
+ dir = File.dirname(__FILE__)
2
+ require "#{dir}/spec_helper"
3
+
4
+ context "" do
5
+ specify "" do
6
+ end
7
+ end
@@ -10,6 +10,10 @@ module BaseSpec
10
10
  def index_with_explicit_assigns
11
11
  render_widget Erector::TestWidget, :foobar => "foobar"
12
12
  end
13
+
14
+ def index_with_render_colon_widget
15
+ render :widget => Erector::TestWidget, :foobar => "foobar"
16
+ end
13
17
  end
14
18
 
15
19
  class Erector::TestWidget < Erector::Widget
@@ -18,7 +22,7 @@ module BaseSpec
18
22
  end
19
23
  end
20
24
 
21
- describe TestWidgetController, "#render_widget" do
25
+ describe TestWidgetController, "rendering widgets" do
22
26
  before do
23
27
  @controller = BaseSpec::TestWidgetController.new
24
28
  @request = ActionController::TestRequest.new
@@ -26,24 +30,39 @@ module BaseSpec
26
30
  @controller.send(:initialize_template_class, @response)
27
31
  @controller.send(:assign_shortcuts, @request, @response)
28
32
  class << @controller
29
- public :rendered_widget
33
+ public :rendered_widget, :render
30
34
  end
31
35
  end
32
36
 
33
- it "assigns to @rendered_widget" do
34
- @controller.rendered_widget.should be_nil
35
- @controller.render_widget Erector::TestWidget
36
- @controller.rendered_widget.should be_instance_of(Erector::TestWidget)
37
- end
37
+ describe "#render_widget" do
38
+ it "assigns to @rendered_widget" do
39
+ @controller.rendered_widget.should be_nil
40
+ @controller.render_widget Erector::TestWidget
41
+ @controller.rendered_widget.should be_instance_of(Erector::TestWidget)
42
+ end
38
43
 
39
- it "instantiates a widget with implicit assigns" do
40
- @controller.index_with_implicit_assigns
41
- @response.body.should == "foobar"
42
- end
44
+ it "instantiates a widget with implicit assigns" do
45
+ @controller.index_with_implicit_assigns
46
+ @response.body.should == "foobar"
47
+ end
43
48
 
44
- it "instantiates a widget with explicit assigns" do
45
- @controller.index_with_explicit_assigns
46
- @response.body.should == "foobar"
49
+ it "instantiates a widget with explicit assigns" do
50
+ @controller.index_with_explicit_assigns
51
+ @response.body.should == "foobar"
52
+ end
53
+ end
54
+
55
+ describe "#render :widget" do
56
+ it "assigns to @rendered_widget" do
57
+ @controller.rendered_widget.should be_nil
58
+ @controller.render :widget => Erector::TestWidget
59
+ @controller.rendered_widget.should be_instance_of(Erector::TestWidget)
60
+ end
61
+
62
+ it "instantiates a widget with explicit assigns" do
63
+ @controller.index_with_render_colon_widget
64
+ @response.body.should == "foobar"
65
+ end
47
66
  end
48
67
  end
49
68
  end
@@ -1,5 +1,7 @@
1
1
  require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper")
2
2
 
3
+ #TODO: This is very confusing with column_a etc. Rewrite to use LastName, FirstName, Email or something like that.
4
+
3
5
  module TableSpec
4
6
  class DefaultsTestTable < Erector::Widgets::Table
5
7
  column :column_a
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: erector
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.25
5
- platform: ruby
4
+ version: 0.2.42
5
+ platform: ""
6
6
  authors:
7
7
  - Pivotal Labs
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-02-26 00:00:00 -08:00
12
+ date: 2008-04-11 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -21,7 +21,7 @@ dependencies:
21
21
  - !ruby/object:Gem::Version
22
22
  version: 1.5.0
23
23
  version:
24
- description: Erector is a Builder-based view framework, inspired by Markaby but overcoming some of its flaws. In Erector all views are objects, not template files, which allows the full power of OO (inheritance, modular decomposition, encapsulation) in views.
24
+ description: Erector is a Builder-like view framework, inspired by Markaby but overcoming some of its flaws. In Erector all views are objects, not template files, which allows the full power of object-oriented programming (inheritance, modular decomposition, encapsulation) in views.
25
25
  email:
26
26
  - alex@pivotallabs.com
27
27
  executables: []
@@ -31,26 +31,29 @@ extensions: []
31
31
  extra_rdoc_files:
32
32
  - README.txt
33
33
  files:
34
+ - spec/erect
34
35
  - spec/erector
36
+ - spec/spec_helper.rb
37
+ - spec/spec_suite.rb
38
+ - spec/view_caching.rb
39
+ - spec/erect/erect_spec.rb
35
40
  - spec/erector/extensions
36
- - spec/erector/extensions/render_widget_spec.rb
37
41
  - spec/erector/widget_spec.rb
38
42
  - spec/erector/widgets
43
+ - spec/erector/extensions/render_widget_spec.rb
39
44
  - spec/erector/widgets/table_spec.rb
40
- - spec/spec_helper.rb
41
- - spec/spec_suite.rb
42
- - spec/view_caching.rb
43
45
  - lib/erector
46
+ - lib/erector.rb
44
47
  - lib/erector/extensions
45
- - lib/erector/extensions/action_controller.rb
46
- - lib/erector/extensions/object.rb
47
48
  - lib/erector/helpers.rb
48
49
  - lib/erector/html_parts.rb
49
50
  - lib/erector/widget.rb
50
51
  - lib/erector/widgets
51
- - lib/erector/widgets/table.rb
52
52
  - lib/erector/widgets.rb
53
- - lib/erector.rb
53
+ - lib/erector/extensions/action_controller.rb
54
+ - lib/erector/extensions/action_view_template_handler.rb
55
+ - lib/erector/extensions/object.rb
56
+ - lib/erector/widgets/table.rb
54
57
  - README.txt
55
58
  has_rdoc: true
56
59
  homepage: http://erector.rubyforge.org
@@ -75,9 +78,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
75
78
  requirements: []
76
79
 
77
80
  rubyforge_project: erector
78
- rubygems_version: 1.0.1
81
+ rubygems_version: 0.9.5
79
82
  signing_key:
80
83
  specification_version: 2
81
- summary: Erector is a Builder-based view framework, inspired by Markaby but overcoming some of its flaws
84
+ summary: Erector is a Builder-like view framework, inspired by Markaby but overcoming some of its flaws
82
85
  test_files: []
83
86