erector 0.4.200 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/erector.rb +0 -1
- data/lib/erector/extensions/object.rb +1 -1
- data/lib/erector/rails/extensions/action_controller.rb +7 -16
- data/lib/erector/rails/extensions/action_controller/1.2.5/action_controller.rb +17 -0
- data/lib/erector/rails/extensions/action_controller/2.2.0/action_controller.rb +26 -0
- data/lib/erector/rails/extensions/widget.rb +18 -22
- data/lib/erector/rails/extensions/widget/1.2.5/widget.rb +18 -0
- data/lib/erector/rails/extensions/widget/2.2.0/widget.rb +23 -0
- data/lib/erector/rails/supported_rails_versions.rb +3 -1
- data/lib/erector/rails/template_handlers/1.2.5/action_view_template_handler.rb +32 -0
- data/lib/erector/rails/template_handlers/2.0.0/action_view_template_handler.rb +36 -0
- data/lib/erector/rails/template_handlers/2.1.0/action_view_template_handler.rb +31 -0
- data/lib/erector/rails/template_handlers/2.2.0/action_view_template_handler.rb +46 -0
- data/lib/erector/rails/template_handlers/action_view_template_handler.rb +11 -89
- data/lib/erector/version.rb +3 -1
- data/lib/erector/widget.rb +128 -37
- data/spec/erector/indentation_spec.rb +7 -6
- data/spec/erector/widget_spec.rb +3 -3
- data/spec/spec_helper.rb +9 -1
- metadata +45 -26
- data/lib/erector/doc.rb +0 -141
- data/spec/erector/doc_spec.rb +0 -55
data/lib/erector.rb
CHANGED
@@ -1,17 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
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
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
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
|
data/lib/erector/version.rb
CHANGED
data/lib/erector/widget.rb
CHANGED
@@ -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.
|
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
|
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
|
-
|
68
|
-
attr_reader :assigns
|
69
|
-
attr_reader :doc
|
70
|
-
attr_reader :block
|
71
|
-
attr_reader :parent
|
67
|
+
cattr_accessor :prettyprint_default
|
72
68
|
|
73
|
-
|
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
|
-
@
|
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
|
-
|
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
|
112
|
-
# calls this widget's #render method
|
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 =
|
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
|
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.
|
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(
|
140
|
-
if
|
141
|
-
@parent =
|
142
|
-
@
|
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
|
-
@
|
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,
|
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 +
|
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
|
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&lt;4" instead of
|
199
208
|
# "2<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
|
-
|
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
|
-
|
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
|
-
@
|
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
|
-
|
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
|
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
|
-
|
284
|
-
@
|
306
|
+
original_output = output
|
307
|
+
@output = ""
|
285
308
|
yield
|
286
|
-
raw(
|
309
|
+
raw(output.to_s)
|
287
310
|
ensure
|
288
|
-
@
|
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
|
-
|
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
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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::
|
129
|
+
Erector::Widget.prettyprint_default = true
|
129
130
|
Erector::Widget.new { br }.to_s.should == "<br />\n"
|
130
|
-
Erector::
|
131
|
+
Erector::Widget.prettyprint_default = false
|
131
132
|
Erector::Widget.new { br }.to_s.should == "<br />"
|
132
133
|
end
|
133
134
|
|
data/spec/erector/widget_spec.rb
CHANGED
@@ -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(@
|
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.
|
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.
|
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
|
data/spec/spec_helper.rb
CHANGED
@@ -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
|
+
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-
|
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/
|
58
|
+
- spec/erector/unicode_builder_spec.rb
|
63
59
|
- spec/erector/widget_spec.rb
|
64
60
|
- spec/erector/indentation_spec.rb
|
65
|
-
- spec/
|
61
|
+
- spec/rails_spec_suite.rb
|
66
62
|
- spec/spec_suite.rb
|
67
|
-
-
|
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/
|
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/
|
80
|
-
- lib/erector/
|
81
|
-
- lib/erector/
|
82
|
-
- lib/erector/
|
83
|
-
- lib/erector/
|
84
|
-
- lib/erector/
|
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/
|
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.
|
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
|
data/lib/erector/doc.rb
DELETED
@@ -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
|
data/spec/erector/doc_spec.rb
DELETED
@@ -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
|