erector 0.7.0 → 0.7.1
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/README.txt +3 -1
- data/VERSION.yml +1 -1
- data/lib/erector.rb +1 -0
- data/lib/erector/externals.rb +29 -0
- data/lib/erector/rails.rb +4 -1
- data/lib/erector/rails/extensions/action_controller.rb +1 -1
- data/lib/erector/rails/extensions/rails_widget.rb +12 -15
- data/lib/erector/rails/extensions/rails_widget/rails_helpers.rb +136 -0
- data/lib/erector/rails/rails_form_builder.rb +20 -0
- data/lib/erector/rails/rails_version.rb +2 -2
- data/lib/erector/rails/template_handlers/ert_handler.rb +32 -0
- data/lib/erector/rails/template_handlers/{action_view_template_handler.rb → rb_handler.rb} +2 -2
- data/lib/erector/widget.rb +42 -16
- data/lib/erector/widgets.rb +3 -1
- data/lib/erector/widgets/environment_badge.rb +29 -0
- data/lib/erector/widgets/field_table.rb +110 -0
- data/lib/erector/widgets/page.rb +158 -0
- data/spec/erector/external_spec.rb +52 -0
- data/spec/erector/widget_spec.rb +50 -6
- data/spec/erector/widgets/field_table_spec.rb +133 -0
- data/spec/erector/widgets/page_spec.rb +29 -0
- data/spec/erector/widgets/table_spec.rb +3 -3
- data/spec/spec_helper.rb +1 -1
- metadata +13 -4
- data/lib/erector/rails/extensions/rails_widget/helpers.rb +0 -110
data/README.txt
CHANGED
@@ -13,6 +13,8 @@ modular decomposition, encapsulation) in views. See the rdoc for the
|
|
13
13
|
Erector::Widget class to learn how to make your own widgets, and visit the
|
14
14
|
project site at http://erector.rubyforge.org for more documentation.
|
15
15
|
|
16
|
+
No, seriously, we've got hella docs at http://erector.rubyforge.org
|
17
|
+
|
16
18
|
== SYNOPSIS
|
17
19
|
|
18
20
|
require 'erector'
|
@@ -25,7 +27,7 @@ project site at http://erector.rubyforge.org for more documentation.
|
|
25
27
|
end
|
26
28
|
body do
|
27
29
|
text "Hello, "
|
28
|
-
b target, :class => 'big'
|
30
|
+
b @target, :class => 'big'
|
29
31
|
text "!"
|
30
32
|
end
|
31
33
|
end
|
data/VERSION.yml
CHANGED
data/lib/erector.rb
CHANGED
@@ -6,6 +6,7 @@ require "active_support/inflector"
|
|
6
6
|
require "active_support/inflections"
|
7
7
|
require "#{dir}/erector/extensions/object"
|
8
8
|
require "#{dir}/erector/raw_string"
|
9
|
+
require "#{dir}/erector/externals"
|
9
10
|
require "#{dir}/erector/widget"
|
10
11
|
require "#{dir}/erector/inline"
|
11
12
|
require "#{dir}/erector/unicode"
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Erector
|
2
|
+
module Externals
|
3
|
+
def externals(type, klass = nil)
|
4
|
+
type = type.to_sym
|
5
|
+
assure_externals_declared(type, klass)
|
6
|
+
x = @@externals[type].dup
|
7
|
+
if klass
|
8
|
+
x.select{|value| @@externals[klass].include?(value)}
|
9
|
+
else
|
10
|
+
x
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def assure_externals_declared(type, klass)
|
15
|
+
@@externals ||= {}
|
16
|
+
@@externals[type] ||= []
|
17
|
+
@@externals[klass] ||= [] if klass
|
18
|
+
end
|
19
|
+
|
20
|
+
def external(type, value)
|
21
|
+
type = type.to_sym
|
22
|
+
klass = self # since it's a class method, self should be the class itself
|
23
|
+
assure_externals_declared(type, klass)
|
24
|
+
@@externals[type] << value unless @@externals[type].include?(value)
|
25
|
+
@@externals[klass] << value unless @@externals[klass].include?(value)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
data/lib/erector/rails.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
dir = File.dirname(__FILE__)
|
2
2
|
require "action_controller"
|
3
3
|
require "#{dir}/rails/rails_version"
|
4
|
+
require "#{dir}/rails/rails_form_builder"
|
4
5
|
require "#{dir}/rails/extensions/rails_widget"
|
5
6
|
require "#{dir}/rails/extensions/action_controller"
|
6
7
|
require "#{dir}/rails/extensions/action_view"
|
7
|
-
require "#{dir}/rails/
|
8
|
+
require "#{dir}/rails/extensions/rails_widget/rails_helpers"
|
9
|
+
require "#{dir}/rails/template_handlers/rb_handler"
|
10
|
+
require "#{dir}/rails/template_handlers/ert_handler"
|
@@ -12,7 +12,7 @@ ActionController::Base.class_eval do
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
response.template.send(:_evaluate_assigns_and_ivars)
|
15
|
-
render :inline => "<% @__widget_class.new(@__widget_assigns
|
15
|
+
render :inline => "<% @__widget_class.new(@__widget_assigns.merge(:parent => self)).to_s %>"
|
16
16
|
end
|
17
17
|
|
18
18
|
def render_with_erector_widget(*options, &block)
|
@@ -8,40 +8,37 @@ module Erector
|
|
8
8
|
process_output_buffer || @output
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
12
|
-
|
11
|
+
def capture_with_parent(&block)
|
12
|
+
parent ? parent.capture(&block) : capture_without_parent(&block)
|
13
13
|
end
|
14
14
|
|
15
|
-
alias_method_chain :capture, :
|
15
|
+
alias_method_chain :capture, :parent
|
16
16
|
|
17
|
-
# This is here to force #
|
17
|
+
# This is here to force #parent.capture to return the output
|
18
18
|
def __in_erb_template; end
|
19
19
|
|
20
20
|
private
|
21
21
|
|
22
22
|
def process_output_buffer
|
23
|
-
if
|
24
|
-
|
25
|
-
buffer.is_a?(String) ? buffer : handle_rjs_buffer
|
23
|
+
if parent.respond_to?(:output_buffer)
|
24
|
+
parent.output_buffer.is_a?(String) ? parent.output_buffer : handle_rjs_buffer
|
26
25
|
else
|
27
26
|
nil
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
31
30
|
def handle_rjs_buffer
|
32
|
-
returning buffer =
|
33
|
-
|
34
|
-
|
35
|
-
buffer <<
|
31
|
+
returning buffer = parent.output_buffer.dup.to_s do
|
32
|
+
parent.output_buffer.clear
|
33
|
+
parent.with_output_buffer(buffer) do
|
34
|
+
buffer << parent.output_buffer.to_s
|
36
35
|
end
|
37
36
|
end
|
38
37
|
end
|
39
38
|
end
|
40
|
-
|
39
|
+
|
41
40
|
class InlineRailsWidget < RailsWidget
|
42
41
|
include Inline
|
43
42
|
end
|
44
|
-
|
45
|
-
end
|
46
43
|
|
47
|
-
|
44
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
module Erector
|
2
|
+
class RailsWidget < Widget
|
3
|
+
module RailsHelpers
|
4
|
+
include ActionController::UrlWriter
|
5
|
+
|
6
|
+
# parent returning raw text whose first parameter is HTML escaped
|
7
|
+
ESCAPED_HELPERS = [
|
8
|
+
:link_to,
|
9
|
+
:link_to_remote,
|
10
|
+
:mail_to,
|
11
|
+
:button_to,
|
12
|
+
:submit_tag,
|
13
|
+
]
|
14
|
+
ESCAPED_HELPERS.each do |method_name|
|
15
|
+
start_line = __LINE__ + 2
|
16
|
+
method_def =<<-METHOD_DEF
|
17
|
+
def #{method_name}(link_text, *args, &block)
|
18
|
+
rawtext(parent.#{method_name}(h(link_text), *args, &block))
|
19
|
+
end
|
20
|
+
METHOD_DEF
|
21
|
+
eval(method_def, binding, __FILE__, start_line)
|
22
|
+
end
|
23
|
+
|
24
|
+
# return text, take block
|
25
|
+
RAW_HELPERS = [
|
26
|
+
:link_to_function,
|
27
|
+
:text_field_tag,
|
28
|
+
:password_field_tag,
|
29
|
+
:check_box_tag,
|
30
|
+
:error_messages_for,
|
31
|
+
:submit_tag,
|
32
|
+
:file_field,
|
33
|
+
:image_tag,
|
34
|
+
:javascript_include_tag,
|
35
|
+
:stylesheet_link_tag,
|
36
|
+
:sortable_element,
|
37
|
+
:sortable_element_js,
|
38
|
+
:text_field_with_auto_complete
|
39
|
+
]
|
40
|
+
RAW_HELPERS.each do |method_name|
|
41
|
+
start_line = __LINE__ + 2
|
42
|
+
method_def =<<-METHOD_DEF
|
43
|
+
def #{method_name}(*args, &block)
|
44
|
+
rawtext parent.#{method_name}(*args, &block)
|
45
|
+
end
|
46
|
+
METHOD_DEF
|
47
|
+
eval(method_def, binding, __FILE__, start_line)
|
48
|
+
end
|
49
|
+
|
50
|
+
CAPTURED_HELPERS_WITHOUT_CONCAT = [
|
51
|
+
:render
|
52
|
+
]
|
53
|
+
CAPTURED_HELPERS_WITHOUT_CONCAT.each do |method_name|
|
54
|
+
start_line = __LINE__ + 2
|
55
|
+
method_def =<<-METHOD_DEF
|
56
|
+
def #{method_name}(*args, &block)
|
57
|
+
captured = parent.capture do
|
58
|
+
parent.concat(parent.#{method_name}(*args, &block))
|
59
|
+
parent.output_buffer.to_s
|
60
|
+
end
|
61
|
+
rawtext(captured)
|
62
|
+
end
|
63
|
+
METHOD_DEF
|
64
|
+
eval(method_def, binding, __FILE__, start_line)
|
65
|
+
end
|
66
|
+
|
67
|
+
CAPTURED_HELPERS_WITH_CONCAT = [
|
68
|
+
:form_tag
|
69
|
+
]
|
70
|
+
CAPTURED_HELPERS_WITH_CONCAT.each do |method_name|
|
71
|
+
start_line = __LINE__ + 2
|
72
|
+
method_def =<<-METHOD_DEF
|
73
|
+
def #{method_name}(*args, &block)
|
74
|
+
captured = parent.capture do
|
75
|
+
parent.#{method_name}(*args, &block)
|
76
|
+
parent.output_buffer.to_s
|
77
|
+
end
|
78
|
+
rawtext(captured)
|
79
|
+
end
|
80
|
+
METHOD_DEF
|
81
|
+
eval(method_def, binding, __FILE__, start_line)
|
82
|
+
end
|
83
|
+
|
84
|
+
def form_for(record_or_name_or_array, *args, &proc)
|
85
|
+
options = args.extract_options!
|
86
|
+
options[:builder] ||= ::Erector::RailsFormBuilder
|
87
|
+
args.push(options)
|
88
|
+
parent.form_for(record_or_name_or_array, *args, &proc)
|
89
|
+
end
|
90
|
+
|
91
|
+
def fields_for(record_or_name_or_array, *args, &proc)
|
92
|
+
options = args.extract_options!
|
93
|
+
options[:builder] ||= ::Erector::RailsFormBuilder
|
94
|
+
args.push(options)
|
95
|
+
parent.fields_for(record_or_name_or_array, *args, &proc)
|
96
|
+
end
|
97
|
+
|
98
|
+
def javascript_include_merged(key)
|
99
|
+
parent.javascript_include_merged(key)
|
100
|
+
end
|
101
|
+
|
102
|
+
def stylesheet_link_merged(key)
|
103
|
+
parent.stylesheet_link_merged(key)
|
104
|
+
end
|
105
|
+
|
106
|
+
def flash
|
107
|
+
parent.controller.send(:flash)
|
108
|
+
end
|
109
|
+
|
110
|
+
def session
|
111
|
+
parent.controller.session
|
112
|
+
end
|
113
|
+
|
114
|
+
def controller
|
115
|
+
parent.controller
|
116
|
+
end
|
117
|
+
|
118
|
+
def cycle(*args)
|
119
|
+
parent.cycle(*args)
|
120
|
+
end
|
121
|
+
|
122
|
+
def simple_format(string)
|
123
|
+
p raw(string.to_s.html_escape.gsub(/\r\n?/, "\n").gsub(/\n/, "<br/>\n"))
|
124
|
+
end
|
125
|
+
|
126
|
+
def time_ago_in_words(*args)
|
127
|
+
parent.time_ago_in_words(*args)
|
128
|
+
end
|
129
|
+
|
130
|
+
def pluralize(*args)
|
131
|
+
parent.pluralize(*args)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
include RailsHelpers
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Erector
|
2
|
+
class RailsFormBuilder
|
3
|
+
attr_reader :parent, :template
|
4
|
+
|
5
|
+
def initialize(object_name, object, template, options, proc)
|
6
|
+
@template = template
|
7
|
+
@parent = ActionView::Helpers::FormBuilder.new(object_name, object, template, options, proc)
|
8
|
+
end
|
9
|
+
|
10
|
+
def method_missing(method_name, *args, &block)
|
11
|
+
if parent.respond_to?(method_name)
|
12
|
+
return_value = parent.send(method_name, *args, &block)
|
13
|
+
template.concat(return_value) if return_value.is_a?(String)
|
14
|
+
return_value
|
15
|
+
else
|
16
|
+
super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module ActionView #:nodoc:
|
2
|
+
module TemplateHandlers #:nodoc:
|
3
|
+
class ErtTemplate < TemplateHandler
|
4
|
+
include Compilable
|
5
|
+
def self.line_offset
|
6
|
+
2
|
7
|
+
end
|
8
|
+
|
9
|
+
ActionView::Template.instance_eval do
|
10
|
+
register_template_handler :ert, ActionView::TemplateHandlers::ErtTemplate
|
11
|
+
end
|
12
|
+
|
13
|
+
def compile(template)
|
14
|
+
[
|
15
|
+
"extend ::Erector::Mixin",
|
16
|
+
"@output_buffer = ''",
|
17
|
+
"memoized_instance_variables = instance_variables.inject({}) do |all, instance_variable|",
|
18
|
+
" all[instance_variable] = instance_variable_get(instance_variable)",
|
19
|
+
" all",
|
20
|
+
"end",
|
21
|
+
"r =::Erector::RailsWidget.inline do",
|
22
|
+
" memoized_instance_variables.each do |instance_variable, value|",
|
23
|
+
" instance_variable_set(instance_variable, value)",
|
24
|
+
" end",
|
25
|
+
template.source,
|
26
|
+
"end",
|
27
|
+
"r.to_s",
|
28
|
+
].join("; ")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
module ActionView #:nodoc:
|
2
2
|
module TemplateHandlers #:nodoc:
|
3
|
-
class
|
3
|
+
class RbHandler < TemplateHandler
|
4
4
|
include Compilable
|
5
5
|
def self.line_offset
|
6
6
|
2
|
7
7
|
end
|
8
8
|
|
9
9
|
ActionView::Template.instance_eval do
|
10
|
-
register_template_handler :rb, ActionView::TemplateHandlers::
|
10
|
+
register_template_handler :rb, ActionView::TemplateHandlers::RbHandler
|
11
11
|
end
|
12
12
|
|
13
13
|
def compile(template)
|
data/lib/erector/widget.rb
CHANGED
@@ -33,6 +33,8 @@ module Erector
|
|
33
33
|
# like a normal method and leaves it up to the caller to emit that string if
|
34
34
|
# it wants.
|
35
35
|
class Widget
|
36
|
+
extend Erector::Externals # 'extend'ing since they're class methods, not instance methods
|
37
|
+
|
36
38
|
class << self
|
37
39
|
def all_tags
|
38
40
|
Erector::Widget.full_tags + Erector::Widget.empty_tags
|
@@ -84,6 +86,7 @@ module Erector
|
|
84
86
|
def after_initialize_parts
|
85
87
|
@after_initialize_parts ||= []
|
86
88
|
end
|
89
|
+
|
87
90
|
end
|
88
91
|
|
89
92
|
# Class method by which widget classes can declare that they need certain
|
@@ -153,21 +156,20 @@ module Erector
|
|
153
156
|
|
154
157
|
SPACES_PER_INDENT = 2
|
155
158
|
|
156
|
-
RESERVED_INSTANCE_VARS = [:helpers, :assigns, :block, :
|
159
|
+
RESERVED_INSTANCE_VARS = [:helpers, :assigns, :block, :output, :prettyprint, :indentation, :at_start_of_line]
|
157
160
|
|
158
161
|
attr_reader *RESERVED_INSTANCE_VARS
|
162
|
+
attr_reader :parent
|
159
163
|
|
160
164
|
def initialize(assigns={}, &block)
|
161
165
|
unless assigns.is_a? Hash
|
162
166
|
raise "Erector's API has changed. Now you should pass only an options hash into Widget.new; the rest come in via to_s, or by using #widget."
|
163
167
|
end
|
164
|
-
if (respond_to? :render) &&
|
165
|
-
!self.method(:render).to_s.include?("(RailsWidget)")
|
166
|
-
raise "Erector's API has changed. You should rename #{self.class}#render to #content."
|
167
|
-
end
|
168
168
|
@assigns = assigns
|
169
|
-
|
170
|
-
@parent
|
169
|
+
assign_instance_variables(assigns)
|
170
|
+
unless @parent
|
171
|
+
@parent = block ? eval("self", block.binding) : nil
|
172
|
+
end
|
171
173
|
@block = block
|
172
174
|
self.class.after_initialize self
|
173
175
|
end
|
@@ -197,14 +199,14 @@ module Erector
|
|
197
199
|
end
|
198
200
|
|
199
201
|
public
|
200
|
-
def
|
202
|
+
def assign_instance_variables (instance_variables)
|
201
203
|
needed = self.class.get_needs.map{|need| need.is_a?(Hash) ? need.keys : need}.flatten
|
202
204
|
assigned = []
|
203
|
-
|
205
|
+
instance_variables.each do |name, value|
|
204
206
|
unless needed.empty? || needed.include?(name)
|
205
207
|
raise "Unknown parameter '#{name}'. #{self.class.name} only accepts #{needed.join(', ')}"
|
206
208
|
end
|
207
|
-
|
209
|
+
assign_instance_variable(name, value)
|
208
210
|
assigned << name
|
209
211
|
end
|
210
212
|
|
@@ -212,7 +214,7 @@ module Erector
|
|
212
214
|
self.class.get_needs.select{|var| var.is_a? Hash}.each do |hash|
|
213
215
|
hash.each_pair do |name, value|
|
214
216
|
unless assigned.include?(name)
|
215
|
-
|
217
|
+
assign_instance_variable(name, value)
|
216
218
|
assigned << name
|
217
219
|
end
|
218
220
|
end
|
@@ -224,9 +226,11 @@ module Erector
|
|
224
226
|
end
|
225
227
|
end
|
226
228
|
|
227
|
-
def
|
229
|
+
def assign_instance_variable (name, value)
|
228
230
|
raise ArgumentError, "Sorry, #{name} is a reserved variable name for Erector. Please choose a different name." if RESERVED_INSTANCE_VARS.include?(name)
|
229
|
-
|
231
|
+
name = name.to_s
|
232
|
+
ivar_name = (name[0..0] == '@' ? name : "@#{name}")
|
233
|
+
instance_variable_set(ivar_name, value)
|
230
234
|
end
|
231
235
|
|
232
236
|
# Render (like to_s) but adding newlines and indentation.
|
@@ -279,14 +283,12 @@ module Erector
|
|
279
283
|
end
|
280
284
|
end
|
281
285
|
|
282
|
-
alias_method :inspect, :to_s
|
283
|
-
|
284
286
|
# Template method which must be overridden by all widget subclasses.
|
285
287
|
# Inside this method you call the magic #element methods which emit HTML
|
286
288
|
# and text to the output string. If you call "super" (or don't override
|
287
289
|
# +content+) then your widget will render any block that was passed into
|
288
290
|
# its constructor. If you want this block to have access to Erector methods
|
289
|
-
# then see Erector::Inline#content.
|
291
|
+
# then see Erector::Inline#content or Erector#inline.
|
290
292
|
def content
|
291
293
|
if @block
|
292
294
|
@block.call
|
@@ -465,6 +467,15 @@ module Erector
|
|
465
467
|
output << "<?xml#{format_sorted(sort_for_xml_declaration(attributes))}?>"
|
466
468
|
end
|
467
469
|
|
470
|
+
# Emits an HTML comment, which looks like this: <!--foo-->
|
471
|
+
# see http://www.w3.org/TR/html4/intro/sgmltut.html#h-3.2.4
|
472
|
+
# Since "Authors should avoid putting two or more adjacent hyphens inside comments,"
|
473
|
+
# we emit a warning if you do that.
|
474
|
+
def comment(text)
|
475
|
+
puts "Warning: Authors should avoid putting two or more adjacent hyphens inside comments." if text =~ /--/
|
476
|
+
output << "<!--#{text}-->"
|
477
|
+
end
|
478
|
+
|
468
479
|
# Creates a whole new output string, executes the block, then converts the
|
469
480
|
# output string to a string and emits it as raw text. If at all possible
|
470
481
|
# you should avoid this method since it hurts performance, and use
|
@@ -562,6 +573,21 @@ module Erector
|
|
562
573
|
false
|
563
574
|
end
|
564
575
|
end
|
576
|
+
|
577
|
+
# emits a jQuery script that is to be run on document ready
|
578
|
+
def jquery(txt)
|
579
|
+
javascript do
|
580
|
+
jquery_ready txt
|
581
|
+
end
|
582
|
+
end
|
583
|
+
|
584
|
+
protected
|
585
|
+
def jquery_ready(txt)
|
586
|
+
rawtext "\n"
|
587
|
+
rawtext "$(document).ready(function(){\n"
|
588
|
+
rawtext txt
|
589
|
+
rawtext "\n});"
|
590
|
+
end
|
565
591
|
|
566
592
|
### internal utility methods
|
567
593
|
|