erector 0.4.200 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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