erector 0.4.200 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,7 +3,6 @@ dir = File.dirname(__FILE__)
3
3
  require 'cgi'
4
4
  require "activesupport"
5
5
  require "#{dir}/erector/extensions/object"
6
- require "#{dir}/erector/doc"
7
6
  require "#{dir}/erector/raw_string"
8
7
  require "#{dir}/erector/widget"
9
8
  require "#{dir}/erector/unicode"
@@ -11,8 +11,8 @@ class Object
11
11
  CGI.unescapeHTML(to_s)
12
12
  end
13
13
 
14
- # OMGWTF :-)
15
14
  def escape_single_quotes
16
15
  self.gsub(/[']/, '\\\\\'')
17
16
  end
18
17
  end
18
+
@@ -1,17 +1,8 @@
1
- ActionController::Base.class_eval do
2
- def render_widget(widget_class, assigns=@assigns)
3
- @__widget_class = widget_class
4
- @__widget_assigns = assigns
5
- add_variables_to_assigns
6
- render :inline => "<% @__widget_class.new(self, @__widget_assigns, StringIO.new(_erbout)).render %>"
7
- end
8
-
9
- def render_with_erector_widget(*options, &block)
10
- if options.first.is_a?(Hash) && widget = options.first.delete(:widget)
11
- render_widget widget, @assigns, &block
12
- else
13
- render_without_erector_widget *options, &block
14
- end
15
- end
16
- alias_method_chain :render, :erector_widget
1
+ dir = File.dirname(__FILE__)
2
+ if (
3
+ ActionController::Base.instance_methods + ActionController::Base.private_instance_methods).
4
+ include?("add_variables_to_assigns")
5
+ require File.expand_path("#{dir}/action_controller/1.2.5/action_controller")
6
+ else
7
+ require File.expand_path("#{dir}/action_controller/2.2.0/action_controller")
17
8
  end
@@ -0,0 +1,17 @@
1
+ ActionController::Base.class_eval do
2
+ def render_widget(widget_class, assigns=@assigns)
3
+ @__widget_class = widget_class
4
+ @__widget_assigns = assigns
5
+ add_variables_to_assigns
6
+ render :inline => "<% @__widget_class.new(self, @__widget_assigns, _erbout).render %>"
7
+ end
8
+
9
+ def render_with_erector_widget(*options, &block)
10
+ if options.first.is_a?(Hash) && widget = options.first.delete(:widget)
11
+ render_widget widget, @assigns, &block
12
+ else
13
+ render_without_erector_widget *options, &block
14
+ end
15
+ end
16
+ alias_method_chain :render, :erector_widget
17
+ end
@@ -0,0 +1,26 @@
1
+ ActionController::Base.class_eval do
2
+ def render_widget(widget_class, assigns=nil)
3
+ @__widget_class = widget_class
4
+ if assigns
5
+ @__widget_assigns = assigns
6
+ else
7
+ @__widget_assigns = {}
8
+ variables = instance_variable_names
9
+ variables -= protected_instance_variables
10
+ variables.each do |name|
11
+ @__widget_assigns[name.sub('@', "")] = instance_variable_get(name)
12
+ end
13
+ end
14
+ response.template.send(:_evaluate_assigns_and_ivars)
15
+ render :inline => "<% @__widget_class.new(self, @__widget_assigns, output_buffer).render %>"
16
+ end
17
+
18
+ def render_with_erector_widget(*options, &block)
19
+ if options.first.is_a?(Hash) && widget = options.first.delete(:widget)
20
+ render_widget widget, @assigns, &block
21
+ else
22
+ render_without_erector_widget *options, &block
23
+ end
24
+ end
25
+ alias_method_chain :render, :erector_widget
26
+ end
@@ -1,26 +1,15 @@
1
1
  module Erector
2
2
  Widget.class_eval do
3
3
  include ActionController::UrlWriter
4
- attr_reader :_erbout
5
-
6
- after_initialize do
7
- @_erbout = doc.string
8
- end
9
-
10
- def fake_erbout
11
- warn "fake_erbout is deprecated. You don't need to use it anymore."
12
- yield
13
- end
14
4
 
15
5
  # helpers returning raw text
16
6
  [
17
- :image_tag,
18
- :javascript_include_tag,
19
- :define_javascript_functions,
20
- :stylesheet_link_tag,
21
- :sortable_element,
22
- :sortable_element_js,
23
- :text_field_with_auto_complete,
7
+ :image_tag,
8
+ :javascript_include_tag,
9
+ :stylesheet_link_tag,
10
+ :sortable_element,
11
+ :sortable_element_js,
12
+ :text_field_with_auto_complete,
24
13
  ].each do |helper_name|
25
14
  define_method helper_name do |*args|
26
15
  begin
@@ -34,11 +23,11 @@ module Erector
34
23
 
35
24
  # helpers returning raw text whose first parameter is HTML escaped
36
25
  [
37
- :link_to,
38
- :link_to_remote,
39
- :mail_to,
40
- :button_to,
41
- :submit_tag,
26
+ :link_to,
27
+ :link_to_remote,
28
+ :mail_to,
29
+ :button_to,
30
+ :submit_tag,
42
31
  ].each do |helper_name|
43
32
 
44
33
  method_def =<<-METHOD_DEF
@@ -118,4 +107,11 @@ module Erector
118
107
  helpers.pluralize(*args)
119
108
  end
120
109
  end
110
+ end
111
+
112
+ dir = File.dirname(__FILE__)
113
+ if ActionView::Base.instance_methods.include?("output_buffer")
114
+ require "#{dir}/widget/2.2.0/widget"
115
+ else
116
+ require "#{dir}/widget/1.2.5/widget"
121
117
  end
@@ -0,0 +1,18 @@
1
+ module Erector
2
+ Widget.class_eval do
3
+ attr_reader :_erbout
4
+
5
+ after_initialize do
6
+ @_erbout = output
7
+ end
8
+
9
+ def define_javascript_functions(*args)
10
+ begin
11
+ text raw(helpers.define_javascript_functions(*args))
12
+ rescue => e
13
+ puts e.backtrace.join("\n\t")
14
+ raise e
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ module Erector
2
+ Widget.class_eval do
3
+ def output
4
+ if helpers.respond_to?(:output_buffer)
5
+ helpers.output_buffer
6
+ else
7
+ @output
8
+ end
9
+ end
10
+
11
+ def capture_with_helpers(&block)
12
+ if helpers
13
+ helpers.capture(&block)
14
+ else
15
+ capture_without_helpers(&block)
16
+ end
17
+ end
18
+ alias_method_chain :capture, :helpers
19
+
20
+ # This is here to force #helpers.capture to return the output
21
+ def __in_erb_template; end
22
+ end
23
+ end
@@ -5,7 +5,9 @@ module Erector
5
5
  "1.99.0" => {'version' => '1.99.0', 'git_tag' => 'v2.0.0_RC1'},
6
6
  "2.0.2" => {'version' => '2.0.2', 'git_tag' => 'v2.0.2'},
7
7
  "2.1.0" => {'version' => '2.1.0', 'git_tag' => 'v2.1.0'},
8
- # "edge" => {'version' => 'edge', 'git_tag' => 'master'},
8
+ "2.2.0" => {'version' => '2.2.0', 'git_tag' => 'v2.2.0'},
9
+ "2.2.2" => {'version' => '2.2.2', 'git_tag' => 'v2.2.2'},
10
+ # "edge" => {'version' => 'edge', 'git_tag' => 'master'}, #TODO: Readd edge support
9
11
  }
10
12
  end
11
13
  end
@@ -0,0 +1,32 @@
1
+ module ActionView #:nodoc:
2
+ module TemplateHandlers #:nodoc:
3
+ class Erector
4
+ def self.line_offset
5
+ 2
6
+ end
7
+
8
+ attr_reader :view
9
+ def initialize(view)
10
+ @view = view
11
+ end
12
+
13
+ def compilable?
14
+ true
15
+ end
16
+
17
+ ActionView::Base.register_template_handler :rb, ActionView::TemplateHandlers::Erector
18
+
19
+ def render(template, local_assigns)
20
+ relative_path_parts = view.first_render.split('/')
21
+ require_dependency view.template_file_path
22
+
23
+ dot_rb = /\.rb$/
24
+ widget_class = relative_path_parts.inject(Views) do |mod, node|
25
+ mod.const_get(node.gsub(dot_rb, '').gsub(".html", "").camelize)
26
+ end
27
+ render_method = view.is_partial_template? ? 'render_partial' : 'render'
28
+ widget_class.new(view, view.assigns).to_s(render_method)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,36 @@
1
+ module ActionView #:nodoc:
2
+ module TemplateHandlers #:nodoc:
3
+ class Erector < TemplateHandler
4
+ def self.line_offset
5
+ 2
6
+ end
7
+
8
+ attr_reader :view
9
+ def initialize(view)
10
+ @view = view
11
+ end
12
+
13
+ def compilable?
14
+ true
15
+ end
16
+ undef :compile
17
+
18
+ ActionView::Base.register_template_handler :rb, ActionView::TemplateHandlers::Erector
19
+
20
+ def render(template, local_assigns)
21
+ relative_path_parts = view.first_render.split('/')
22
+ file_name = relative_path_parts.last
23
+ require_dependency(view.template_file_path)
24
+
25
+ dot_rb = /\.rb$/
26
+ widget_class = relative_path_parts.inject(Views) do |mod, node|
27
+ mod.const_get(node.gsub(dot_rb, '').gsub(".html", "").camelize)
28
+ end
29
+ render_method = view.is_partial_template? ? 'render_partial' : 'render'
30
+ widget = widget_class.new(view, view.assigns)
31
+ widget.to_s(render_method)
32
+ end
33
+ end
34
+ end
35
+ end
36
+
@@ -0,0 +1,31 @@
1
+ module ActionView #:nodoc:
2
+ module TemplateHandlers #:nodoc:
3
+ class Erector < TemplateHandler
4
+ include Compilable
5
+ def self.line_offset
6
+ 2
7
+ end
8
+
9
+ ActionView::Template.instance_eval do
10
+ register_template_handler :rb, ActionView::TemplateHandlers::Erector
11
+ end
12
+
13
+ def compile(template)
14
+ relative_path_parts = template.path.split('/')
15
+
16
+ is_partial = relative_path_parts.last =~ /^_/
17
+ require_dependency File.expand_path(template.filename)
18
+
19
+ widget_class_parts = relative_path_parts.inject(['Views']) do |class_parts, node|
20
+ class_parts << node.gsub(/^_/, "").gsub(/(\.html)?\.rb$/, '').classify
21
+ class_parts
22
+ end
23
+ widget_class_name = widget_class_parts.join("::")
24
+ render_method = is_partial ? 'render_partial' : 'render'
25
+
26
+ erb_template = "<% #{widget_class_name}.new(self, controller.assigns, _erbout).#{render_method} %>"
27
+ ::ERB.new(erb_template, nil, ActionView::Base.erb_trim_mode).src
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,46 @@
1
+ module ActionView #:nodoc:
2
+ module TemplateHandlers #:nodoc:
3
+ class Erector < TemplateHandler
4
+ include Compilable
5
+ def self.line_offset
6
+ 2
7
+ end
8
+
9
+ ActionView::Template.instance_eval do
10
+ register_template_handler :rb, ActionView::TemplateHandlers::Erector
11
+ end
12
+
13
+ def compile(template)
14
+ relative_path_parts = template.path.split('/')
15
+
16
+ is_partial = relative_path_parts.last =~ /^_/
17
+ require_dependency File.expand_path(template.filename)
18
+
19
+ widget_class_parts = relative_path_parts.inject(['Views']) do |class_parts, node|
20
+ class_parts << node.gsub(/^_/, "").gsub(/(\.html)?\.rb$/, '').classify
21
+ class_parts
22
+ end
23
+ widget_class_name = widget_class_parts.join("::")
24
+ render_method = is_partial ? 'render_partial' : 'render'
25
+
26
+ erb_template = <<-ERB
27
+ <%
28
+ assigns = instance_variables.inject({}) do |hash, name|
29
+ hash[name.sub('@', "")] = instance_variable_get(name)
30
+ hash
31
+ end
32
+
33
+ widget = #{widget_class_name}.new(self, assigns, output_buffer)
34
+ widget.#{render_method}
35
+ %>
36
+ ERB
37
+ ::ERB.new(
38
+ erb_template,
39
+ nil,
40
+ ::ActionView::TemplateHandlers::ERB.erb_trim_mode,
41
+ "@output_buffer"
42
+ ).src
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,92 +1,14 @@
1
- module ActionView #:nodoc:
2
- module TemplateHandlers #:nodoc:
3
- class Erector
4
- def self.line_offset
5
- 2
6
- end
7
-
8
- attr_reader :view
9
- def initialize(view)
10
- @view = view
11
- end
12
-
13
- def compilable?
14
- true
15
- end
16
-
17
- if ActionView.const_defined?(:Template)
18
- ActionView::Template.instance_eval do
19
- register_template_handler :rb, ActionView::TemplateHandlers::Erector
20
- end
21
-
22
- def compile_template(template)
23
- relative_path_parts = view.first_render.split('/')
24
- require_dependency view.finder.pick_template(
25
- template.path,
26
- view.finder.pick_template_extension(template.path)
27
- )
28
-
29
- dot_rb = /\.rb$/
30
- widget_class_parts = relative_path_parts.inject(['Views']) do |class_parts, node|
31
- class_parts << node.gsub(dot_rb, '').camelize
32
- class_parts
33
- end
34
- widget_class_name = widget_class_parts.join("::")
35
- render_method = template.is_a?(ActionView::PartialTemplate) ? 'render_partial' : 'render'
36
-
37
- erb_template = "<% #{widget_class_name}.new(self, controller.assigns, StringIO.new(_erbout)).#{render_method} %>"
38
- ::ERB.new(erb_template, nil, @view.erb_trim_mode).src
39
- end
40
-
41
- def render(template)
42
- relative_path_parts = view.first_render.split('/')
43
- require_dependency view.finder.pick_template(
44
- template.path,
45
- view.finder.pick_template_extension(template.path)
46
- )
47
-
48
- dot_rb = /\.rb$/
49
- widget_class = relative_path_parts.inject(Views) do |mod, node|
50
- mod.const_get(node.gsub(dot_rb, '').camelize)
51
- end
52
- render_method = template.is_a?(ActionView::PartialTemplate) ? 'render_partial' : 'render'
53
- widget_class.new(view, view.assigns).to_s(render_method)
54
- end
55
- else
56
- ActionView::Base.instance_eval do
57
- if respond_to?(:register_template_handler)
58
- register_template_handler :rb, ActionView::TemplateHandlers::Erector
59
- end
60
- end
61
-
62
- def compile(template)
63
- relative_path_parts = view.first_render.split('/')
64
- require_dependency view.template_file_path
65
-
66
- dot_rb = /\.rb$/
67
- widget_class_parts = relative_path_parts.inject(['Views']) do |class_parts, node|
68
- class_parts << node.gsub(dot_rb, '').camelize
69
- class_parts
70
- end
71
- widget_class_name = widget_class_parts.join("::")
72
- render_method = view.is_partial_template? ? 'render_partial' : 'render'
73
-
74
- erb_template = "<% #{widget_class_name}.new(self, controller.assigns, StringIO.new(_erbout)).#{render_method} %>"
75
- ::ERB.new(erb_template, nil, @view.erb_trim_mode).src
76
- end
77
-
78
- def render(template, local_assigns)
79
- relative_path_parts = view.first_render.split('/')
80
- require_dependency view.template_file_path
81
-
82
- dot_rb = /\.rb$/
83
- widget_class = relative_path_parts.inject(Views) do |mod, node|
84
- mod.const_get(node.gsub(dot_rb, '').camelize)
85
- end
86
- render_method = view.is_partial_template? ? 'render_partial' : 'render'
87
- widget_class.new(view, view.assigns).to_s(render_method)
88
- end
89
- end
1
+ dir = File.dirname(__FILE__)
2
+ if ActionView.const_defined?(:TemplateHandlers)
3
+ if ::ActionView::TemplateHandlers::const_defined?(:Compilable)
4
+ if ActionView.const_defined?(:TemplateHandlers) && ::ActionView::TemplateHandlers::ERB.respond_to?(:erb_trim_mode)
5
+ require File.expand_path("#{dir}/2.2.0/action_view_template_handler")
6
+ else
7
+ require File.expand_path("#{dir}/2.1.0/action_view_template_handler")
90
8
  end
9
+ else
10
+ require File.expand_path("#{dir}/2.0.0/action_view_template_handler")
91
11
  end
12
+ else
13
+ require File.expand_path("#{dir}/1.2.5/action_view_template_handler")
92
14
  end
@@ -1,6 +1,8 @@
1
1
  ##
2
2
  # Erector view framework
3
3
  module Erector
4
- VERSION = "0.4.200"
4
+ if !Erector.const_defined?(:VERSION)
5
+ VERSION = "0.5.0"
6
+ end
5
7
  end
6
8
 
@@ -12,11 +12,11 @@ module Erector
12
12
  # To render a widget from the outside, instantiate it and call its +to_s+ method.
13
13
  #
14
14
  # To call one widget from another, inside the parent widget's render method, instantiate the child widget and call
15
- # its +render_to+ method, passing in +self+ (or self.doc if you prefer). This assures that the same Doc stream
15
+ # its +render_to+ method, passing in +self+ (or self.output if you prefer). This assures that the same output
16
16
  # is used, which gives better performance than using +capture+ or +to_s+.
17
17
  #
18
18
  # In this documentation we've tried to keep the distinction clear between methods that *emit* text and those that
19
- # *return* text. "Emit" means that it writes Doc to the doc stream; "return" means that it returns a string
19
+ # *return* text. "Emit" means that it writes to the output stream; "return" means that it returns a string
20
20
  # like a normal method and leaves it up to the caller to emit that string if it wants.
21
21
  class Widget
22
22
  class << self
@@ -32,14 +32,14 @@ module Erector
32
32
  # tags which can contain other stuff
33
33
  def full_tags
34
34
  [
35
- 'a', 'acronym', 'address', 'b', 'bdo', 'big', 'blockquote', 'body',
36
- 'button', 'caption', 'center', 'cite', 'code',
35
+ 'a', 'abbr', 'acronym', 'address', 'b', 'bdo', 'big', 'blockquote', 'body',
36
+ 'button', 'caption', 'center', 'cite', 'code', 'col', 'colgroup',
37
37
  'dd', 'del', 'div', 'dl', 'dt', 'em',
38
38
  'fieldset', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'html', 'i',
39
39
  'iframe', 'ins', 'kbd', 'label', 'legend', 'li', 'map',
40
40
  'noframes', 'noscript', 'ol', 'optgroup', 'option', 'p', 'param', 'pre',
41
41
  'samp', 'script', 'select', 'small', 'span', 'strong', 'style', 'sub', 'sup',
42
- 'table', 'tbody', 'td', 'textarea', 'th', 'thead', 'title', 'tr', 'tt', 'u', 'ul', 'var'
42
+ 'table', 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'title', 'tr', 'tt', 'u', 'ul', 'var'
43
43
  ]
44
44
  end
45
45
 
@@ -64,19 +64,28 @@ module Erector
64
64
  end
65
65
  end
66
66
 
67
- attr_reader :helpers
68
- attr_reader :assigns
69
- attr_reader :doc
70
- attr_reader :block
71
- attr_reader :parent
67
+ cattr_accessor :prettyprint_default
72
68
 
73
- def initialize(helpers=nil, assigns={}, io = StringIO.new(""), &block)
69
+ NON_NEWLINEY = {'i' => true, 'b' => true, 'small' => true,
70
+ 'img' => true, 'span' => true, 'a' => true,
71
+ 'input' => true, 'textarea' => true, 'button' => true, 'select' => true
72
+ }
73
+
74
+ SPACES_PER_INDENT = 2
75
+
76
+ attr_reader :helpers, :assigns, :block, :parent, :output
77
+ attr_accessor :enable_prettyprint
78
+
79
+ def initialize(helpers=nil, assigns={}, output = "", &block)
74
80
  @assigns = assigns
75
81
  assign_locals(assigns)
76
82
  @helpers = helpers
77
83
  @parent = block ? eval("self", block.binding) : nil
78
- @doc = Doc.new(io)
84
+ @output = output
79
85
  @block = block
86
+ @at_start_of_line = true
87
+ @indent = 0
88
+ @enable_prettyprint = prettyprint_default
80
89
  self.class.after_initialize self
81
90
  end
82
91
 
@@ -99,7 +108,7 @@ module Erector
99
108
  # This flag should be set prior to any rendering being done
100
109
  # (for example, calls to to_s or to_pretty).
101
110
  def enable_prettyprint(enable)
102
- @doc.enable_prettyprint = enable
111
+ self.enable_prettyprint = enable
103
112
  self
104
113
  end
105
114
 
@@ -108,8 +117,8 @@ module Erector
108
117
  enable_prettyprint(true).to_s
109
118
  end
110
119
 
111
- # Entry point for rendering a widget (and all its children). This method creates a new Doc doc stream,
112
- # calls this widget's #render method, converts the Doc to a string, and returns the string.
120
+ # Entry point for rendering a widget (and all its children). This method creates a new output string,
121
+ # calls this widget's #render method and returns the string.
113
122
  #
114
123
  # If it's called again later
115
124
  # then it returns the earlier rendered string, which leads to higher performance, but may have confusing
@@ -120,13 +129,13 @@ module Erector
120
129
  # If it's useful we should add a test for it. -ac
121
130
  return @__to_s if @__to_s
122
131
  send(render_method_name, &blk)
123
- @__to_s = @doc.to_s
132
+ @__to_s = output.to_s
124
133
  end
125
134
 
126
135
  alias_method :inspect, :to_s
127
136
 
128
137
  # Template method which must be overridden by all widget subclasses. Inside this method you call the magic
129
- # #element methods which emit HTML and text to the Doc stream.
138
+ # #element methods which emit HTML and text to the output string.
130
139
  def render
131
140
  if @block
132
141
  instance_eval(&@block)
@@ -134,14 +143,14 @@ module Erector
134
143
  end
135
144
 
136
145
  # To call one widget from another, inside the parent widget's render method, instantiate the child widget and call
137
- # its +render_to+ method, passing in +self+ (or self.doc if you prefer). This assures that the same Doc stream
146
+ # its +render_to+ method, passing in +self+ (or self.output if you prefer). This assures that the same output string
138
147
  # is used, which gives better performance than using +capture+ or +to_s+.
139
- def render_to(doc_or_widget)
140
- if doc_or_widget.is_a?(Widget)
141
- @parent = doc_or_widget
142
- @doc = @parent.doc
148
+ def render_to(output_or_widget)
149
+ if output_or_widget.is_a?(Widget)
150
+ @parent = output_or_widget
151
+ @output = @parent.output
143
152
  else
144
- @doc = doc_or_widget
153
+ @output = output_or_widget
145
154
  end
146
155
  render
147
156
  end
@@ -151,7 +160,7 @@ module Erector
151
160
  # This is an experimental erector feature which may disappear in future
152
161
  # versions of erector (see #widget in widget_spec in the Erector tests).
153
162
  def widget(widget_class, assigns={}, &block)
154
- child = widget_class.new(helpers, assigns, doc.output, &block)
163
+ child = widget_class.new(helpers, assigns, output, &block)
155
164
  child.render
156
165
  end
157
166
 
@@ -174,7 +183,7 @@ module Erector
174
183
  # When calling one of these magic methods, put attributes in the default hash. If there is a string parameter,
175
184
  # then it is used as the contents. If there is a block, then it is executed (yielded), and the string parameter is ignored.
176
185
  # The block will usually be in the scope of the child widget, which means it has access to all the
177
- # methods of Widget, which will eventually end up appending text to the +doc+ Doc stream. See how
186
+ # methods of Widget, which will eventually end up appending text to the +output+ string. See how
178
187
  # elegant it is? Not confusing at all if you don't think about it.
179
188
  #
180
189
  def element(*args, &block)
@@ -193,7 +202,7 @@ module Erector
193
202
  __empty_element__(*args, &block)
194
203
  end
195
204
 
196
- # Returns an HTML-escaped version of its parameter. Leaves the Doc stream untouched. Note that
205
+ # Returns an HTML-escaped version of its parameter. Leaves the output string untouched. Note that
197
206
  # the #text method automatically HTML-escapes its parameter, so be careful *not* to do something like
198
207
  # text(h("2<4")) since that will double-escape the less-than sign (you'll get "2&amp;lt;4" instead of
199
208
  # "2&lt;4").
@@ -203,7 +212,11 @@ module Erector
203
212
 
204
213
  # Emits an open tag, comprising '<', tag name, optional attributes, and '>'
205
214
  def open_tag(tag_name, attributes={})
206
- @doc.open_tag tag_name, attributes
215
+ indent_for_open_tag(tag_name)
216
+ @indent += SPACES_PER_INDENT
217
+
218
+ output.concat "<#{tag_name}#{format_attributes(attributes)}>"
219
+ @at_start_of_line = false
207
220
  end
208
221
 
209
222
  # Emits text. If a string is passed in, it will be HTML-escaped.
@@ -212,7 +225,9 @@ module Erector
212
225
  # If another kind of object is passed in, the result of calling
213
226
  # its to_s method will be treated as a string would be.
214
227
  def text(value)
215
- @doc.text value
228
+ output.concat(value.html_escape)
229
+ @at_start_of_line = false
230
+ nil
216
231
  end
217
232
 
218
233
  # Returns text which will *not* be HTML-escaped.
@@ -250,7 +265,15 @@ module Erector
250
265
 
251
266
  # Emits a close tag, consisting of '<', tag name, and '>'
252
267
  def close_tag(tag_name)
253
- @doc.close_tag tag_name
268
+ @indent -= SPACES_PER_INDENT
269
+ indent()
270
+
271
+ output.concat("</#{tag_name}>")
272
+
273
+ if newliney(tag_name)
274
+ output.concat "\n"
275
+ @at_start_of_line = true
276
+ end
254
277
  end
255
278
 
256
279
  # Emits the result of joining the elements in array with the separator.
@@ -269,23 +292,23 @@ module Erector
269
292
 
270
293
  # Emits an XML instruction, which looks like this: <?xml version=\"1.0\" encoding=\"UTF-8\"?>
271
294
  def instruct(attributes={:version => "1.0", :encoding => "UTF-8"})
272
- @doc.instruct attributes
295
+ output.concat "<?xml#{format_sorted(sort_for_xml_declaration(attributes))}?>"
273
296
  end
274
297
 
275
298
  # Deprecated synonym of instruct
276
299
  alias_method :instruct!, :instruct
277
300
 
278
- # Creates a whole new doc stream, executes the block, then converts the doc stream to a string and
301
+ # Creates a whole new output string, executes the block, then converts the output string to a string and
279
302
  # emits it as raw text. If at all possible you should avoid this method since it hurts performance,
280
303
  # and use #render_to instead.
281
304
  def capture(&block)
282
305
  begin
283
- original_doc = @doc
284
- @doc = Doc.new(StringIO.new)
306
+ original_output = output
307
+ @output = ""
285
308
  yield
286
- raw(@doc.to_s)
309
+ raw(output.to_s)
287
310
  ensure
288
- @doc = original_doc
311
+ @output = original_output
289
312
  end
290
313
  end
291
314
 
@@ -360,6 +383,14 @@ module Erector
360
383
  def url(href)
361
384
  a href, :href => href
362
385
  end
386
+
387
+ def newliney(tag_name)
388
+ if @enable_prettyprint
389
+ !NON_NEWLINEY.include?(tag_name)
390
+ else
391
+ false
392
+ end
393
+ end
363
394
 
364
395
  ### internal utility methods
365
396
 
@@ -401,8 +432,68 @@ protected
401
432
  end
402
433
 
403
434
  def __empty_element__(tag_name, attributes={})
404
- @doc.empty_element tag_name, attributes
435
+ indent_for_open_tag(tag_name)
436
+
437
+ output.concat "<#{tag_name}#{format_attributes(attributes)} />"
438
+
439
+ if newliney(tag_name)
440
+ output.concat "\n"
441
+ @at_start_of_line = true
442
+ end
443
+ end
444
+
445
+ def indent_for_open_tag(tag_name)
446
+ if !@at_start_of_line && newliney(tag_name)
447
+ output.concat "\n"
448
+ @at_start_of_line = true
449
+ end
450
+
451
+ indent()
452
+ end
453
+
454
+ def indent()
455
+ if @at_start_of_line
456
+ output.concat " " * @indent
457
+ end
458
+ end
459
+
460
+ def format_attributes(attributes)
461
+ if !attributes || attributes.empty?
462
+ ""
463
+ else
464
+ format_sorted(sorted(attributes))
465
+ end
466
+ end
467
+
468
+ def format_sorted(sorted)
469
+ results = ['']
470
+ sorted.each do |key, value|
471
+ if value
472
+ if value.is_a?(Array)
473
+ value = [value].flatten.join(' ')
474
+ end
475
+ results << "#{key}=\"#{value.html_escape}\""
476
+ end
477
+ end
478
+ return results.join(' ')
479
+ end
480
+
481
+ def sorted(attributes)
482
+ stringized = []
483
+ attributes.each do |key, value|
484
+ stringized << [key.to_s, value]
485
+ end
486
+ return stringized.sort
487
+ end
488
+
489
+ def sort_for_xml_declaration(attributes)
490
+ # correct order is "version, encoding, standalone" (XML 1.0 section 2.8).
491
+ # But we only try to put version before encoding for now.
492
+ stringized = []
493
+ attributes.each do |key, value|
494
+ stringized << [key.to_s, value]
495
+ end
496
+ return stringized.sort{|a, b| b <=> a}
405
497
  end
406
-
407
498
  end
408
499
  end
@@ -3,10 +3,11 @@ require File.expand_path("#{File.dirname(__FILE__)}/../spec_helper")
3
3
  describe "indentation" do
4
4
 
5
5
  it "can detect newliney tags" do
6
- doc = Erector::Doc.new(StringIO.new(""))
7
- doc.enable_prettyprint = true
8
- doc.newliney("i").should == false
9
- doc.newliney("table").should == true
6
+ widget = ::Erector::Widget.new
7
+ string = widget.output
8
+ widget.enable_prettyprint = true
9
+ widget.newliney("i").should == false
10
+ widget.newliney("table").should == true
10
11
  end
11
12
 
12
13
  it "should not add newline for non-newliney tags" do
@@ -125,9 +126,9 @@ END
125
126
 
126
127
  it "can turn newlines on/off via global variable" do
127
128
  Erector::Widget.new { br }.to_s.should == "<br />"
128
- Erector::Doc.prettyprint_default = true
129
+ Erector::Widget.prettyprint_default = true
129
130
  Erector::Widget.new { br }.to_s.should == "<br />\n"
130
- Erector::Doc.prettyprint_default = false
131
+ Erector::Widget.prettyprint_default = false
131
132
  Erector::Widget.new { br }.to_s.should == "<br />"
132
133
  end
133
134
 
@@ -622,13 +622,13 @@ module WidgetSpec
622
622
  class B < Erector::Widget
623
623
  def render
624
624
  text "B"
625
- A.new.render_to(@doc)
625
+ A.new.render_to(@output)
626
626
  text "B"
627
627
  end
628
628
  end
629
629
  b = B.new
630
630
  b.to_s.should == "B<p>A</p>B"
631
- b.doc.size.should == 10 # B, <p>, A, </p>, B
631
+ b.output.size.should == 10 # B, <p>, A, </p>, B
632
632
  end
633
633
 
634
634
  it "renders to a widget's doc" do
@@ -641,7 +641,7 @@ module WidgetSpec
641
641
  end
642
642
  b = B.new
643
643
  b.to_s.should == "B<p>A</p>B"
644
- b.doc.size.should == 10 # B, <p>, A, </p>, B
644
+ b.output.size.should == 10 # B, <p>, A, </p>, B
645
645
  end
646
646
 
647
647
  it "passing a widget to text method renders it" do
@@ -12,7 +12,6 @@ require "erector/erect"
12
12
  require "erector/erected"
13
13
  require "spec"
14
14
 
15
-
16
15
  Spec::Runner.configure do |config|
17
16
  config.mock_with :rr
18
17
  end
@@ -43,3 +42,12 @@ end
43
42
  # def print(string="")
44
43
  # super string + "\s(#{caller.first.match(/(\w+\.\w+:\d+)|Rakefile:\d+/)[0]})"
45
44
  # end
45
+ unless '1.9'.respond_to?(:force_encoding)
46
+ String.class_eval do
47
+ begin
48
+ remove_method :chars
49
+ rescue NameError
50
+ # OK
51
+ end
52
+ end
53
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: erector
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.200
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pivotal Labs
@@ -9,11 +9,12 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-10-12 00:00:00 -04:00
12
+ date: 2008-12-14 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: treetop
17
+ type: :runtime
17
18
  version_requirement:
18
19
  version_requirements: !ruby/object:Gem::Requirement
19
20
  requirements:
@@ -23,6 +24,7 @@ dependencies:
23
24
  version:
24
25
  - !ruby/object:Gem::Dependency
25
26
  name: rake
27
+ type: :runtime
26
28
  version_requirement:
27
29
  version_requirements: !ruby/object:Gem::Requirement
28
30
  requirements:
@@ -32,6 +34,7 @@ dependencies:
32
34
  version:
33
35
  - !ruby/object:Gem::Dependency
34
36
  name: hoe
37
+ type: :runtime
35
38
  version_requirement:
36
39
  version_requirements: !ruby/object:Gem::Requirement
37
40
  requirements:
@@ -49,47 +52,63 @@ extensions: []
49
52
  extra_rdoc_files:
50
53
  - README.txt
51
54
  files:
52
- - spec/spec_helper.rb
53
- - spec/core_spec_suite.rb
54
- - spec/rails_spec_suite.rb
55
- - spec/erect
56
- - spec/erect/rhtml_parser_spec.rb
57
- - spec/erect/erect_spec.rb
58
- - spec/erect/erected_spec.rb
59
55
  - spec/erector
60
56
  - spec/erector/widgets
61
57
  - spec/erector/widgets/table_spec.rb
62
- - spec/erector/doc_spec.rb
58
+ - spec/erector/unicode_builder_spec.rb
63
59
  - spec/erector/widget_spec.rb
64
60
  - spec/erector/indentation_spec.rb
65
- - spec/erector/unicode_builder_spec.rb
61
+ - spec/rails_spec_suite.rb
66
62
  - spec/spec_suite.rb
67
- - lib/erector.rb
63
+ - spec/core_spec_suite.rb
64
+ - spec/spec_helper.rb
65
+ - spec/erect
66
+ - spec/erect/erected_spec.rb
67
+ - spec/erect/erect_spec.rb
68
+ - spec/erect/rhtml_parser_spec.rb
68
69
  - lib/erector
69
- - lib/erector/widgets
70
- - lib/erector/widgets/table.rb
71
70
  - lib/erector/rails
72
- - lib/erector/rails/supported_rails_versions.rb
73
71
  - lib/erector/rails/extensions
74
72
  - lib/erector/rails/extensions/action_controller.rb
75
- - lib/erector/rails/extensions/widget.rb
73
+ - lib/erector/rails/extensions/action_controller
74
+ - lib/erector/rails/extensions/action_controller/1.2.5
75
+ - lib/erector/rails/extensions/action_controller/1.2.5/action_controller.rb
76
+ - lib/erector/rails/extensions/action_controller/2.2.0
77
+ - lib/erector/rails/extensions/action_controller/2.2.0/action_controller.rb
78
+ - lib/erector/rails/extensions/widget
79
+ - lib/erector/rails/extensions/widget/1.2.5
80
+ - lib/erector/rails/extensions/widget/1.2.5/widget.rb
81
+ - lib/erector/rails/extensions/widget/2.2.0
82
+ - lib/erector/rails/extensions/widget/2.2.0/widget.rb
76
83
  - lib/erector/rails/extensions/action_view.rb
84
+ - lib/erector/rails/extensions/widget.rb
77
85
  - lib/erector/rails/template_handlers
78
86
  - lib/erector/rails/template_handlers/action_view_template_handler.rb
79
- - lib/erector/raw_string.rb
80
- - lib/erector/widgets.rb
81
- - lib/erector/widget.rb
82
- - lib/erector/erect.rb
83
- - lib/erector/unicode_builder.rb
84
- - lib/erector/doc.rb
87
+ - lib/erector/rails/template_handlers/2.0.0
88
+ - lib/erector/rails/template_handlers/2.0.0/action_view_template_handler.rb
89
+ - lib/erector/rails/template_handlers/2.1.0
90
+ - lib/erector/rails/template_handlers/2.1.0/action_view_template_handler.rb
91
+ - lib/erector/rails/template_handlers/1.2.5
92
+ - lib/erector/rails/template_handlers/1.2.5/action_view_template_handler.rb
93
+ - lib/erector/rails/template_handlers/2.2.0
94
+ - lib/erector/rails/template_handlers/2.2.0/action_view_template_handler.rb
95
+ - lib/erector/rails/supported_rails_versions.rb
96
+ - lib/erector/widgets
97
+ - lib/erector/widgets/table.rb
98
+ - lib/erector/rails.rb
85
99
  - lib/erector/extensions
86
100
  - lib/erector/extensions/object.rb
87
- - lib/erector/unicode.rb
88
- - lib/erector/rhtml.treetop
89
- - lib/erector/rails.rb
101
+ - lib/erector/erect.rb
90
102
  - lib/erector/indenting.rb
103
+ - lib/erector/rhtml.treetop
104
+ - lib/erector/raw_string.rb
91
105
  - lib/erector/version.rb
106
+ - lib/erector/widgets.rb
107
+ - lib/erector/unicode.rb
108
+ - lib/erector/unicode_builder.rb
109
+ - lib/erector/widget.rb
92
110
  - lib/erector/erected.rb
111
+ - lib/erector.rb
93
112
  - README.txt
94
113
  - bin/erect
95
114
  has_rdoc: true
@@ -115,7 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
115
134
  requirements: []
116
135
 
117
136
  rubyforge_project: erector
118
- rubygems_version: 1.1.1
137
+ rubygems_version: 1.3.1
119
138
  signing_key:
120
139
  specification_version: 2
121
140
  summary: Erector is a Builder-like view framework, inspired by Markaby but overcoming some of its flaws
@@ -1,141 +0,0 @@
1
- module Erector
2
- # A proxy to an IO object that adds methods to add xml.
3
- class Doc
4
-
5
- cattr_accessor :prettyprint_default
6
-
7
- NON_NEWLINEY = {'i' => true, 'b' => true, 'small' => true,
8
- 'img' => true, 'span' => true, 'a' => true,
9
- 'input' => true, 'textarea' => true, 'button' => true, 'select' => true
10
- }
11
-
12
- SPACES_PER_INDENT = 2
13
-
14
- attr_accessor :enable_prettyprint
15
-
16
- def initialize(output, options = {})
17
- @output = output
18
- @at_start_of_line = true
19
- @indent = 0
20
- @enable_prettyprint = prettyprint_default
21
- end
22
-
23
- def output
24
- unless @output.eof?
25
- @output.seek(0, IO::SEEK_END)
26
- end
27
- @output
28
- end
29
-
30
- def newliney(tag_name)
31
- if @enable_prettyprint
32
- !NON_NEWLINEY.include?(tag_name)
33
- else
34
- false
35
- end
36
- end
37
-
38
- def open_tag(tag_name, attributes={})
39
- indent_for_open_tag(tag_name)
40
- @indent += SPACES_PER_INDENT
41
-
42
- output.print "<#{tag_name}#{format_attributes(attributes)}>"
43
- @at_start_of_line = false
44
- end
45
-
46
- def text(value)
47
- output.print(value.html_escape)
48
- @at_start_of_line = false
49
- nil
50
- end
51
-
52
- def close_tag(tag_name)
53
- @indent -= SPACES_PER_INDENT
54
- indent()
55
-
56
- output.print("</#{tag_name}>")
57
-
58
- if newliney(tag_name)
59
- output.print "\n"
60
- @at_start_of_line = true
61
- end
62
- end
63
-
64
- def indent_for_open_tag(tag_name)
65
- if !@at_start_of_line && newliney(tag_name)
66
- output.print "\n"
67
- @at_start_of_line = true
68
- end
69
-
70
- indent()
71
- end
72
-
73
- def indent()
74
- if @at_start_of_line
75
- output.print " " * @indent
76
- end
77
- end
78
-
79
- def empty_element(tag_name, attributes={})
80
- indent_for_open_tag(tag_name)
81
-
82
- output.print "<#{tag_name}#{format_attributes(attributes)} />"
83
-
84
- if newliney(tag_name)
85
- output.print "\n"
86
- @at_start_of_line = true
87
- end
88
- end
89
-
90
- def instruct(attributes={:version => "1.0", :encoding => "UTF-8"})
91
- output.print "<?xml#{format_sorted(sort_for_xml_declaration(attributes))}?>"
92
- end
93
-
94
- def to_s
95
- output.string
96
- end
97
-
98
- protected
99
- def method_missing(method_name, *args, &blk)
100
- output.__send__(method_name, *args, &blk)
101
- rescue NoMethodError => e
102
- raise NoMethodError, "undefined method `#{method_name}' for #{inspect}"
103
- end
104
-
105
- def format_attributes(attributes)
106
- return "" if !attributes || attributes.empty?
107
- return format_sorted(sorted(attributes))
108
- end
109
-
110
- def format_sorted(sorted)
111
- results = ['']
112
- sorted.each do |key, value|
113
- if value
114
- if value.is_a?(Array)
115
- value = [value].flatten.join(' ')
116
- end
117
- results << "#{key}=\"#{value.html_escape}\""
118
- end
119
- end
120
- return results.join(' ')
121
- end
122
-
123
- def sorted(attributes)
124
- stringized = []
125
- attributes.each do |key, value|
126
- stringized << [key.to_s, value]
127
- end
128
- return stringized.sort
129
- end
130
-
131
- def sort_for_xml_declaration(attributes)
132
- # correct order is "version, encoding, standalone" (XML 1.0 section 2.8).
133
- # But we only try to put version before encoding for now.
134
- stringized = []
135
- attributes.each do |key, value|
136
- stringized << [key.to_s, value]
137
- end
138
- return stringized.sort{|a, b| b <=> a}
139
- end
140
- end
141
- end
@@ -1,55 +0,0 @@
1
- require File.expand_path("#{File.dirname(__FILE__)}/../spec_helper")
2
-
3
- module Erector
4
- describe Doc do
5
- describe "#output" do
6
- it "seeks to the end of the buffer" do
7
- string = "Hello"
8
- io = StringIO.new(string)
9
- doc = Doc.new(io)
10
-
11
- string.concat(" World")
12
- doc.text " Again"
13
-
14
- string.should == "Hello World Again"
15
- end
16
- end
17
-
18
- describe "#method_missing" do
19
- context "when passed in io object raises a NoMethodError" do
20
- context "when the passed in io object respond_to? method is false" do
21
- attr_reader :io
22
- before do
23
- @io = StringIO.new
24
- io.should_not respond_to(:foo)
25
- lambda {io.foo}.should raise_error(NoMethodError, /undefined method `foo' for #<StringIO/)
26
- end
27
-
28
- it "raises a NoMethodError that originates from within Doc#method_missing" do
29
- doc = Doc.new(io)
30
- lambda do
31
- doc.foo
32
- end.should raise_error(NoMethodError, /undefined method `foo' for #<Erector::Doc/)
33
- end
34
- end
35
-
36
- context "when the passed in io object respond_to? method is true" do
37
- attr_reader :io
38
- before do
39
- @io = StringIO.new
40
- stub(io).foo {raise NoMethodError, "Stubbed NoMethodError"}
41
- io.should respond_to(:foo)
42
- lambda {io.foo}.should raise_error(NoMethodError, "Stubbed NoMethodError")
43
- end
44
-
45
- it "raises a NoMethodError that originates from within Doc#method_missing" do
46
- doc = Doc.new(io)
47
- lambda do
48
- doc.foo
49
- end.should raise_error(NoMethodError, /undefined method `foo' for #<Erector::Doc/)
50
- end
51
- end
52
- end
53
- end
54
- end
55
- end