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.
- 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
|