Markaby 0.6.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/CHANGELOG.rdoc +43 -0
- data/Markaby.gemspec +100 -0
- data/README.rdoc +262 -0
- data/Rakefile +48 -0
- data/VERSION +1 -0
- data/garlic.rb +29 -0
- data/init.rb +6 -0
- data/lib/markaby/builder.rb +275 -0
- data/lib/markaby/builder_tags.rb +64 -0
- data/lib/markaby/cssproxy.rb +55 -0
- data/lib/markaby/kernel_method.rb +7 -0
- data/lib/markaby/rails/current.rb +41 -0
- data/lib/markaby/rails/deprecated.rb +122 -0
- data/lib/markaby/rails.rb +68 -0
- data/lib/markaby/tags.rb +193 -0
- data/lib/markaby/tilt.rb +21 -0
- data/lib/markaby.rb +30 -0
- data/spec/markaby/builder_spec.rb +40 -0
- data/spec/markaby/css_proxy_spec.rb +44 -0
- data/spec/markaby/fragment_spec.rb +7 -0
- data/spec/markaby/markaby_other_static.mab +1 -0
- data/spec/markaby/markaby_spec.rb +207 -0
- data/spec/markaby/rails/spec_helper.rb +20 -0
- data/spec/markaby/rails/views/markaby/_a_partial.mab +3 -0
- data/spec/markaby/rails/views/markaby/_partial_child_with_locals.mab +1 -0
- data/spec/markaby/rails/views/markaby/access_to_helpers.mab +1 -0
- data/spec/markaby/rails/views/markaby/broken.mab +7 -0
- data/spec/markaby/rails/views/markaby/correct_template_values.mab +5 -0
- data/spec/markaby/rails/views/markaby/no_values_passed.mab +3 -0
- data/spec/markaby/rails/views/markaby/partial_parent.mab +1 -0
- data/spec/markaby/rails/views/markaby/partial_parent_with_locals.mab +7 -0
- data/spec/markaby/rails/views/markaby/render_erb_without_explicit_render_call.erb +1 -0
- data/spec/markaby/rails/views/markaby/render_explicit_but_empty_markaby_layout.mab +0 -0
- data/spec/markaby/rails/views/markaby/render_mab_without_explicit_render_call.mab +3 -0
- data/spec/markaby/rails/views/markaby/render_with_ivar.mab +3 -0
- data/spec/markaby/rails/views/markaby/renders_erb.rhtml +1 -0
- data/spec/markaby/rails_spec.rb +190 -0
- data/spec/markaby/rails_version_spec.rb +37 -0
- data/spec/markaby/tilt/erb.erb +1 -0
- data/spec/markaby/tilt/locals.mab +1 -0
- data/spec/markaby/tilt/markaby.mab +1 -0
- data/spec/markaby/tilt/markaby_other_static.mab +1 -0
- data/spec/markaby/tilt/render_twice.mab +1 -0
- data/spec/markaby/tilt/scope.mab +1 -0
- data/spec/markaby/tilt/yielding.mab +2 -0
- data/spec/markaby/tilt_spec.rb +86 -0
- data/spec/markaby/xml_markup_spec.rb +9 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +39 -0
- metadata +126 -0
@@ -0,0 +1,275 @@
|
|
1
|
+
require 'markaby/tags'
|
2
|
+
require 'markaby/builder_tags'
|
3
|
+
|
4
|
+
module Markaby
|
5
|
+
# The Markaby::Builder class is the central gear in the system. When using
|
6
|
+
# from Ruby code, this is the only class you need to instantiate directly.
|
7
|
+
#
|
8
|
+
# mab = Markaby::Builder.new
|
9
|
+
# mab.html do
|
10
|
+
# head { title "Boats.com" }
|
11
|
+
# body do
|
12
|
+
# h1 "Boats.com has great deals"
|
13
|
+
# ul do
|
14
|
+
# li "$49 for a canoe"
|
15
|
+
# li "$39 for a raft"
|
16
|
+
# li "$29 for a huge boot that floats and can fit 5 people"
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
# puts mab.to_s
|
21
|
+
#
|
22
|
+
class Builder
|
23
|
+
include Markaby::BuilderTags
|
24
|
+
|
25
|
+
DEFAULT_OPTIONS = {
|
26
|
+
:indent => 0,
|
27
|
+
:output_helpers => true,
|
28
|
+
:output_xml_instruction => true,
|
29
|
+
:output_meta_tag => true,
|
30
|
+
:auto_validation => true,
|
31
|
+
:tagset => Markaby::XHTMLTransitional,
|
32
|
+
:root_attributes => {
|
33
|
+
:xmlns => 'http://www.w3.org/1999/xhtml',
|
34
|
+
:'xml:lang' => 'en',
|
35
|
+
:lang => 'en'
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
@@options = DEFAULT_OPTIONS.dup
|
40
|
+
|
41
|
+
def self.restore_defaults!
|
42
|
+
@@options = DEFAULT_OPTIONS.dup
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.set(option, value)
|
46
|
+
@@options[option] = value
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.get(option)
|
50
|
+
@@options[option]
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.ignored_helpers
|
54
|
+
@@ignored_helpers ||= []
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.ignore_helpers(*helpers)
|
58
|
+
ignored_helpers.concat helpers
|
59
|
+
end
|
60
|
+
|
61
|
+
attr_accessor :output_helpers, :tagset
|
62
|
+
|
63
|
+
# Create a Markaby builder object. Pass in a hash of variable assignments to
|
64
|
+
# +assigns+ which will be available as instance variables inside tag construction
|
65
|
+
# blocks. If an object is passed in to +helper+, its methods will be available
|
66
|
+
# from those same blocks.
|
67
|
+
#
|
68
|
+
# Pass in a +block+ to new and the block will be evaluated.
|
69
|
+
#
|
70
|
+
# mab = Markaby::Builder.new {
|
71
|
+
# html do
|
72
|
+
# body do
|
73
|
+
# h1 "Matching Mole"
|
74
|
+
# end
|
75
|
+
# end
|
76
|
+
# }
|
77
|
+
#
|
78
|
+
def initialize(assigns = {}, helper = nil, &block)
|
79
|
+
@streams = [[]]
|
80
|
+
@assigns = assigns.dup
|
81
|
+
@_helper = helper
|
82
|
+
@used_ids = {}
|
83
|
+
|
84
|
+
@@options.each do |k, v|
|
85
|
+
instance_variable_set("@#{k}", @assigns.delete(k) || v)
|
86
|
+
end
|
87
|
+
|
88
|
+
@assigns.each do |k, v|
|
89
|
+
instance_variable_set("@#{k}", v)
|
90
|
+
end
|
91
|
+
|
92
|
+
@builder = XmlMarkup.new(:indent => @indent, :target => @streams.last)
|
93
|
+
|
94
|
+
instance_eval(&block) if block
|
95
|
+
end
|
96
|
+
|
97
|
+
def helper=(helper)
|
98
|
+
@_helper = helper
|
99
|
+
end
|
100
|
+
|
101
|
+
def metaclass(&block)
|
102
|
+
metaclass = class << self; self; end
|
103
|
+
metaclass.class_eval(&block)
|
104
|
+
end
|
105
|
+
|
106
|
+
private :metaclass
|
107
|
+
|
108
|
+
def locals=(locals)
|
109
|
+
locals.each do |key, value|
|
110
|
+
metaclass do
|
111
|
+
define_method key do
|
112
|
+
value
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Returns a string containing the HTML stream. Internally, the stream is stored as an Array.
|
119
|
+
def to_s
|
120
|
+
@streams.last.to_s
|
121
|
+
end
|
122
|
+
|
123
|
+
# Write a +string+ to the HTML stream without escaping it.
|
124
|
+
def text(string)
|
125
|
+
@builder << string.to_s
|
126
|
+
nil
|
127
|
+
end
|
128
|
+
alias_method :<<, :text
|
129
|
+
alias_method :concat, :text
|
130
|
+
|
131
|
+
# Captures the HTML code built inside the +block+. This is done by creating a new
|
132
|
+
# stream for the builder object, running the block and passing back its stream as a string.
|
133
|
+
#
|
134
|
+
# >> Markaby::Builder.new.capture { h1 "TEST"; h2 "CAPTURE ME" }
|
135
|
+
# => "<h1>TITLE</h1>\n<h2>CAPTURE ME</h2>\n"
|
136
|
+
#
|
137
|
+
def capture(&block)
|
138
|
+
@streams.push(@builder.target = [])
|
139
|
+
@builder.level += 1
|
140
|
+
str = instance_eval(&block)
|
141
|
+
str = @streams.last.join if @streams.last.any?
|
142
|
+
@streams.pop
|
143
|
+
@builder.level -= 1
|
144
|
+
@builder.target = @streams.last
|
145
|
+
str
|
146
|
+
end
|
147
|
+
|
148
|
+
# Create a tag named +tag+. Other than the first argument which is the tag name,
|
149
|
+
# the arguments are the same as the tags implemented via method_missing.
|
150
|
+
def tag!(tag, *args, &block)
|
151
|
+
ele_id = nil
|
152
|
+
if @auto_validation && @tagset
|
153
|
+
if !@tagset.tagset.has_key?(tag)
|
154
|
+
raise InvalidXhtmlError, "no element `#{tag}' for #{tagset.doctype}"
|
155
|
+
elsif args.last.respond_to?(:to_hash)
|
156
|
+
attrs = args.last.to_hash
|
157
|
+
|
158
|
+
if @tagset.forms.include?(tag) && attrs[:id]
|
159
|
+
attrs[:name] ||= attrs[:id]
|
160
|
+
end
|
161
|
+
|
162
|
+
attrs.each do |k, v|
|
163
|
+
atname = k.to_s.downcase.intern
|
164
|
+
unless k =~ /:/ or @tagset.tagset[tag].include? atname
|
165
|
+
raise InvalidXhtmlError, "no attribute `#{k}' on #{tag} elements"
|
166
|
+
end
|
167
|
+
if atname == :id
|
168
|
+
ele_id = v.to_s
|
169
|
+
if @used_ids.has_key? ele_id
|
170
|
+
raise InvalidXhtmlError, "id `#{ele_id}' already used (id's must be unique)."
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
if block
|
178
|
+
str = capture(&block)
|
179
|
+
block = proc { text(str) }
|
180
|
+
end
|
181
|
+
|
182
|
+
f = fragment { @builder.method_missing(tag, *args, &block) }
|
183
|
+
@used_ids[ele_id] = f if ele_id
|
184
|
+
f
|
185
|
+
end
|
186
|
+
|
187
|
+
private
|
188
|
+
|
189
|
+
# This method is used to intercept calls to helper methods and instance
|
190
|
+
# variables. Here is the order of interception:
|
191
|
+
#
|
192
|
+
# * If +sym+ is a helper method, the helper method is called
|
193
|
+
# and output to the stream.
|
194
|
+
# * If +sym+ is a Builder::XmlMarkup method, it is passed on to the builder object.
|
195
|
+
# * If +sym+ is also the name of an instance variable, the
|
196
|
+
# value of the instance variable is returned.
|
197
|
+
# * If +sym+ has come this far and no +tagset+ is found, +sym+ and its arguments are passed to tag!
|
198
|
+
# * If a tagset is found, though, +NoMethodError+ is raised.
|
199
|
+
#
|
200
|
+
# method_missing used to be the lynchpin in Markaby, but it's no longer used to handle
|
201
|
+
# HTML tags. See html_tag for that.
|
202
|
+
def method_missing(sym, *args, &block)
|
203
|
+
if @_helper.respond_to?(sym, true) && !self.class.ignored_helpers.include?(sym)
|
204
|
+
r = @_helper.send(sym, *args, &block)
|
205
|
+
if @output_helpers && r.respond_to?(:to_str)
|
206
|
+
fragment { @builder << r }
|
207
|
+
else
|
208
|
+
r
|
209
|
+
end
|
210
|
+
elsif @assigns.has_key?(sym)
|
211
|
+
@assigns[sym]
|
212
|
+
elsif @assigns.has_key?(stringy_key = sym.to_s)
|
213
|
+
# Rails' ActionView assigns hash has string keys for
|
214
|
+
# instance variables that are defined in the controller.
|
215
|
+
@assigns[stringy_key]
|
216
|
+
elsif instance_variables.include?(ivar = "@#{sym}")
|
217
|
+
instance_variable_get(ivar)
|
218
|
+
elsif @_helper && @_helper.instance_variables.include?(ivar)
|
219
|
+
@_helper.instance_variable_get(ivar)
|
220
|
+
elsif ::Builder::XmlMarkup.instance_methods.include?(sym.to_s)
|
221
|
+
@builder.__send__(sym, *args, &block)
|
222
|
+
elsif !@tagset
|
223
|
+
tag!(sym, *args, &block)
|
224
|
+
else
|
225
|
+
super
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def fragment
|
230
|
+
stream = @streams.last
|
231
|
+
start = stream.length
|
232
|
+
yield
|
233
|
+
length = stream.length - start
|
234
|
+
Fragment.new(stream, start, length)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
# Every tag method in Markaby returns a Fragment. If any method gets called on the Fragment,
|
239
|
+
# the tag is removed from the Markaby stream and given back as a string. Usually the fragment
|
240
|
+
# is never used, though, and the stream stays intact.
|
241
|
+
#
|
242
|
+
# For a more practical explanation, check out the README.
|
243
|
+
class Fragment < ::Builder::BlankSlate
|
244
|
+
def initialize(*args)
|
245
|
+
@stream, @start, @length = args
|
246
|
+
@transformed_stream = false
|
247
|
+
end
|
248
|
+
|
249
|
+
private
|
250
|
+
|
251
|
+
def method_missing(*args, &block)
|
252
|
+
transform_stream unless transformed_stream?
|
253
|
+
@str.__send__(*args, &block)
|
254
|
+
end
|
255
|
+
|
256
|
+
def transform_stream
|
257
|
+
@transformed_stream = true
|
258
|
+
|
259
|
+
# We can't do @stream.slice!(@start, @length),
|
260
|
+
# as it would invalidate the @starts and @lengths of other Fragment instances.
|
261
|
+
@str = @stream[@start, @length].to_s
|
262
|
+
@stream[@start, @length] = [nil] * @length
|
263
|
+
end
|
264
|
+
|
265
|
+
def transformed_stream?
|
266
|
+
@transformed_stream
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
class XmlMarkup < ::Builder::XmlMarkup
|
271
|
+
attr_accessor :target, :level
|
272
|
+
|
273
|
+
private :method_missing
|
274
|
+
end
|
275
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Markaby
|
2
|
+
module BuilderTags
|
3
|
+
(XHTMLTransitional.tags - [:head]).each do |k|
|
4
|
+
class_eval <<-CODE, __FILE__, __LINE__
|
5
|
+
def #{k}(*args, &block)
|
6
|
+
html_tag(#{k.inspect}, *args, &block)
|
7
|
+
end
|
8
|
+
CODE
|
9
|
+
end
|
10
|
+
|
11
|
+
# Every HTML tag method goes through an html_tag call. So, calling <tt>div</tt> is equivalent
|
12
|
+
# to calling <tt>html_tag(:div)</tt>. All HTML tags in Markaby's list are given generated wrappers
|
13
|
+
# for this method.
|
14
|
+
#
|
15
|
+
# If the @auto_validation setting is on, this method will check for many common mistakes which
|
16
|
+
# could lead to invalid XHTML.
|
17
|
+
def html_tag(sym, *args, &block)
|
18
|
+
if @auto_validation && @tagset.self_closing.include?(sym) && block
|
19
|
+
raise InvalidXhtmlError, "the `#{sym}' element is self-closing, please remove the block"
|
20
|
+
elsif args.empty? && !block
|
21
|
+
CssProxy.new(self, @streams.last, sym)
|
22
|
+
else
|
23
|
+
tag!(sym, *args, &block)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Builds a head tag. Adds a <tt>meta</tt> tag inside with Content-Type
|
28
|
+
# set to <tt>text/html; charset=utf-8</tt>.
|
29
|
+
def head(*args, &block)
|
30
|
+
tag!(:head, *args) do
|
31
|
+
tag!(:meta, "http-equiv" => "Content-Type", "content" => "text/html; charset=utf-8") if @output_meta_tag
|
32
|
+
instance_eval(&block)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Builds an html tag. An XML 1.0 instruction and an XHTML 1.0 Transitional doctype
|
37
|
+
# are prepended. Also assumes <tt>:xmlns => "http://www.w3.org/1999/xhtml",
|
38
|
+
# :lang => "en"</tt>.
|
39
|
+
def xhtml_transitional(attrs = {}, &block)
|
40
|
+
self.tagset = Markaby::XHTMLTransitional
|
41
|
+
xhtml_html(attrs, &block)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Builds an html tag with XHTML 1.0 Strict doctype instead.
|
45
|
+
def xhtml_strict(attrs = {}, &block)
|
46
|
+
self.tagset = Markaby::XHTMLStrict
|
47
|
+
xhtml_html(attrs, &block)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Builds an html tag with XHTML 1.0 Frameset doctype instead.
|
51
|
+
def xhtml_frameset(attrs = {}, &block)
|
52
|
+
self.tagset = Markaby::XHTMLFrameset
|
53
|
+
xhtml_html(attrs, &block)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def xhtml_html(attrs = {}, &block)
|
59
|
+
instruct! if @output_xml_instruction
|
60
|
+
declare!(:DOCTYPE, :html, :PUBLIC, *tagset.doctype)
|
61
|
+
tag!(:html, @root_attributes.merge(attrs), &block)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Markaby
|
2
|
+
# Class used by Markaby::Builder to store element options. Methods called
|
3
|
+
# against the CssProxy object are added as element classes or IDs.
|
4
|
+
#
|
5
|
+
# See the README for examples.
|
6
|
+
class CssProxy
|
7
|
+
def initialize(builder, stream, sym)
|
8
|
+
@builder = builder
|
9
|
+
@stream = stream
|
10
|
+
@sym = sym
|
11
|
+
@attrs = {}
|
12
|
+
|
13
|
+
@original_stream_length = @stream.length
|
14
|
+
|
15
|
+
@builder.tag! sym
|
16
|
+
end
|
17
|
+
|
18
|
+
def respond_to?(sym, include_private = false)
|
19
|
+
include_private || !private_methods.include?(sym.to_s) ? true : false
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# Adds attributes to an element. Bang methods set the :id attribute.
|
25
|
+
# Other methods add to the :class attribute.
|
26
|
+
def method_missing(id_or_class, *args, &block)
|
27
|
+
if id_or_class.to_s =~ /(.*)!$/
|
28
|
+
@attrs[:id] = $1
|
29
|
+
else
|
30
|
+
id = id_or_class
|
31
|
+
@attrs[:class] = @attrs[:class] ? "#{@attrs[:class]} #{id}".strip : id
|
32
|
+
end
|
33
|
+
|
34
|
+
unless args.empty?
|
35
|
+
if args.last.respond_to? :to_hash
|
36
|
+
@attrs.merge! args.pop.to_hash
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
args.push(@attrs)
|
41
|
+
|
42
|
+
while @stream.length > @original_stream_length
|
43
|
+
@stream.pop
|
44
|
+
end
|
45
|
+
|
46
|
+
if block
|
47
|
+
@builder.tag! @sym, *args, &block
|
48
|
+
else
|
49
|
+
@builder.tag! @sym, *args
|
50
|
+
end
|
51
|
+
|
52
|
+
self
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Markaby
|
2
|
+
module Rails
|
3
|
+
class TemplateHandler < ::ActionView::TemplateHandler
|
4
|
+
def compile(template, local_assigns={})
|
5
|
+
<<-CODE
|
6
|
+
handler = Markaby::Rails::TemplateHandler.new
|
7
|
+
handler.view = self
|
8
|
+
handler.render(lambda { #{template.source} }, local_assigns)
|
9
|
+
CODE
|
10
|
+
end
|
11
|
+
|
12
|
+
def render(template, local_assigns = (template.respond_to?(:locals) ? template.locals : {}))
|
13
|
+
builder = Markaby::Builder.new(instance_variables.merge(local_assigns), @view)
|
14
|
+
|
15
|
+
template.is_a?(Proc) ?
|
16
|
+
builder.instance_eval(&template) :
|
17
|
+
builder.instance_eval(template.source)
|
18
|
+
|
19
|
+
builder.to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_accessor :view
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def instance_variables
|
27
|
+
instance_variable_hash(@view)
|
28
|
+
end
|
29
|
+
|
30
|
+
def instance_variable_hash(object)
|
31
|
+
returning Hash.new do |hash|
|
32
|
+
object.instance_variables.each do |var_name|
|
33
|
+
hash[var_name.gsub("@", "")] = object.instance_variable_get(var_name)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
ActionView::Template.register_template_handler(:mab, Markaby::Rails::TemplateHandler)
|
@@ -0,0 +1,122 @@
|
|
1
|
+
module ActionView # :nodoc:
|
2
|
+
class Base # :nodoc:
|
3
|
+
def render_template(template_extension, template, file_path = nil, local_assigns = {})
|
4
|
+
if handler = @@template_handlers[template_extension]
|
5
|
+
template ||= read_template_file(file_path, template_extension)
|
6
|
+
handler.new(self).render(template, local_assigns, file_path)
|
7
|
+
else
|
8
|
+
compile_and_render_template(template_extension, template, file_path, local_assigns)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module Markaby
|
15
|
+
module Rails
|
16
|
+
class Template
|
17
|
+
|
18
|
+
def self.builder_class=(builder)
|
19
|
+
@@builder_class = builder
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.builder_class
|
23
|
+
@@builder_class ||= Builder
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_accessor :source, :path
|
27
|
+
|
28
|
+
def initialize(source)
|
29
|
+
@source = source.to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
def render(*args)
|
33
|
+
output = self.class.builder_class.new(*args)
|
34
|
+
|
35
|
+
if path
|
36
|
+
output.instance_eval source, path
|
37
|
+
else
|
38
|
+
output.instance_eval source
|
39
|
+
end
|
40
|
+
|
41
|
+
output.to_s
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Markaby helpers for Rails.
|
46
|
+
module ActionControllerHelpers
|
47
|
+
# Returns a string of HTML built from the attached +block+. Any +options+ are
|
48
|
+
# passed into the render method.
|
49
|
+
#
|
50
|
+
# Use this method in your controllers to output Markaby directly from inside.
|
51
|
+
def render_markaby(options = {}, &block)
|
52
|
+
render options.merge({ :text => Builder.new(options[:locals], self, &block).to_s })
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class ActionViewTemplateHandler # :nodoc:
|
57
|
+
def initialize(action_view)
|
58
|
+
@action_view = action_view
|
59
|
+
end
|
60
|
+
def render(template, local_assigns, file_path)
|
61
|
+
template = Template.new(template)
|
62
|
+
template.path = file_path
|
63
|
+
template.render(@action_view.assigns.merge(local_assigns), @action_view)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class Builder < ::Markaby::Builder # :nodoc:
|
68
|
+
def initialize(*args, &block)
|
69
|
+
super *args, &block
|
70
|
+
|
71
|
+
@assigns.each { |k, v| @helpers.instance_variable_set("@#{k}", v) }
|
72
|
+
end
|
73
|
+
|
74
|
+
def flash(*args)
|
75
|
+
@helpers.controller.send(:flash, *args)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Emulate ERB to satisfy helpers like <tt>form_for</tt>.
|
79
|
+
def _erbout
|
80
|
+
@_erbout ||= FauxErbout.new(self)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Content_for will store the given block in an instance variable for later use
|
84
|
+
# in another template or in the layout.
|
85
|
+
#
|
86
|
+
# The name of the instance variable is content_for_<name> to stay consistent
|
87
|
+
# with @content_for_layout which is used by ActionView's layouts.
|
88
|
+
#
|
89
|
+
# Example:
|
90
|
+
#
|
91
|
+
# content_for("header") do
|
92
|
+
# h1 "Half Shark and Half Lion"
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# If used several times, the variable will contain all the parts concatenated.
|
96
|
+
def content_for(name, &block)
|
97
|
+
@helpers.assigns["content_for_#{name}"] =
|
98
|
+
eval("@content_for_#{name} = (@content_for_#{name} || '') + capture(&block)")
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
Template.builder_class = Builder
|
103
|
+
|
104
|
+
class FauxErbout < ::Builder::BlankSlate # :nodoc:
|
105
|
+
def initialize(builder)
|
106
|
+
@builder = builder
|
107
|
+
end
|
108
|
+
def nil? # see ActionView::Helpers::CaptureHelper#capture
|
109
|
+
true
|
110
|
+
end
|
111
|
+
def method_missing(*args, &block)
|
112
|
+
@builder.send *args, &block
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
if defined? ActionView::Template and ActionView::Template.respond_to? :register_template_handler
|
118
|
+
ActionView::Template
|
119
|
+
else
|
120
|
+
ActionView::Base
|
121
|
+
end.register_template_handler(:mab, Markaby::Rails::ActionViewTemplateHandler)
|
122
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Markaby
|
2
|
+
module Rails
|
3
|
+
DEPRECATED_RAILS_VERSIONS = [
|
4
|
+
"1.2.2",
|
5
|
+
"1.2.3",
|
6
|
+
"1.2.4",
|
7
|
+
"1.2.5",
|
8
|
+
"1.2.6",
|
9
|
+
]
|
10
|
+
|
11
|
+
FULLY_SUPPORTED_RAILS_VERSIONS = [
|
12
|
+
# "2.0.0",
|
13
|
+
# "2.0.1",
|
14
|
+
# "2.0.2",
|
15
|
+
# "2.0.3",
|
16
|
+
# "2.0.4",
|
17
|
+
# "2.0.5",
|
18
|
+
"2.1.0",
|
19
|
+
"2.1.1",
|
20
|
+
"2.1.2",
|
21
|
+
"2.2.0",
|
22
|
+
"2.2.1",
|
23
|
+
"2.2.2",
|
24
|
+
"2.2.3",
|
25
|
+
# "2.3.0",
|
26
|
+
"2.3.1",
|
27
|
+
"2.3.2",
|
28
|
+
"2.3.2.1",
|
29
|
+
"2.3.3",
|
30
|
+
"2.3.3.1",
|
31
|
+
"2.3.4"
|
32
|
+
]
|
33
|
+
|
34
|
+
SUPPORTED_RAILS_VERSIONS = DEPRECATED_RAILS_VERSIONS + FULLY_SUPPORTED_RAILS_VERSIONS
|
35
|
+
|
36
|
+
class << self
|
37
|
+
def load
|
38
|
+
check_rails_version
|
39
|
+
|
40
|
+
if deprecated_rails_version?
|
41
|
+
require File.dirname(__FILE__) + "/rails/deprecated"
|
42
|
+
else
|
43
|
+
require File.dirname(__FILE__) + "/rails/current"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def deprecated_rails_version?
|
48
|
+
DEPRECATED_RAILS_VERSIONS.include?(detected_rails_version)
|
49
|
+
end
|
50
|
+
|
51
|
+
def check_rails_version
|
52
|
+
unless SUPPORTED_RAILS_VERSIONS.include?(detected_rails_version)
|
53
|
+
error_message = "Cannot load markaby under rails version #{detected_rails_version}. "
|
54
|
+
error_message << "See Markaby::Rails::SUPPORTED_RAILS_VERSIONS for exactly that, or redefine this constant."
|
55
|
+
raise LoadError, error_message
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def detected_rails_version
|
62
|
+
if defined?(::Rails)
|
63
|
+
::Rails::VERSION::STRING
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|