markaby 0.5 → 0.6.6
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/CHANGELOG.rdoc +79 -0
- data/Markaby.gemspec +103 -0
- data/{README → README.rdoc} +14 -6
- data/Rakefile +71 -14
- data/VERSION +1 -0
- data/garlic.rb +29 -0
- data/init.rb +6 -0
- data/lib/markaby.rb +4 -9
- data/lib/markaby/builder.rb +156 -143
- data/lib/markaby/builder_tags.rb +64 -0
- data/lib/markaby/cssproxy.rb +36 -34
- data/lib/markaby/kernel_method.rb +7 -0
- data/lib/markaby/rails.rb +64 -39
- data/lib/markaby/rails/current.rb +46 -0
- data/lib/markaby/rails/deprecated.rb +124 -0
- data/lib/markaby/rails/rails_builder.rb +50 -0
- data/lib/markaby/tags.rb +158 -130
- data/lib/markaby/tilt.rb +21 -0
- data/spec/markaby/builder_spec.rb +118 -0
- data/spec/markaby/css_proxy_spec.rb +47 -0
- data/spec/markaby/fragment_spec.rb +10 -0
- data/spec/markaby/markaby_other_static.mab +1 -0
- data/spec/markaby/markaby_spec.rb +232 -0
- data/spec/markaby/rails/spec_helper.rb +21 -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/form_for.mab +2 -0
- data/spec/markaby/rails/views/markaby/form_for_with_fields.mab +3 -0
- data/spec/markaby/rails/views/markaby/form_for_with_multiple_fields.mab +4 -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 +249 -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/spec.opts +2 -0
- data/spec/spec_helper.rb +39 -0
- metadata +132 -52
- data/lib/markaby/metaid.rb +0 -16
- data/lib/markaby/template.rb +0 -12
- data/setup.rb +0 -1551
- data/test/test_markaby.rb +0 -109
- data/tools/rakehelp.rb +0 -106
@@ -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
|
data/lib/markaby/cssproxy.rb
CHANGED
@@ -4,50 +4,52 @@ module Markaby
|
|
4
4
|
#
|
5
5
|
# See the README for examples.
|
6
6
|
class CssProxy
|
7
|
+
def initialize(builder, stream, sym)
|
8
|
+
@builder = builder
|
9
|
+
@stream = stream
|
10
|
+
@sym = sym
|
11
|
+
@attrs = {}
|
7
12
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
@opts = opts
|
12
|
-
@blk = blk
|
13
|
+
@original_stream_length = @stream.length
|
14
|
+
|
15
|
+
@builder.tag! sym
|
13
16
|
end
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
# tag. Like the default `img' method included with Markaby automatically sets an
|
18
|
-
# empty alt attribute.
|
19
|
-
def merge!(opts)
|
20
|
-
@opts.merge! opts
|
21
|
-
self
|
17
|
+
|
18
|
+
def respond_to?(sym, include_private = false)
|
19
|
+
include_private || !private_methods.map { |m| m.to_sym }.include?(sym.to_sym) ? true : false
|
22
20
|
end
|
23
21
|
|
22
|
+
private
|
23
|
+
|
24
24
|
# Adds attributes to an element. Bang methods set the :id attribute.
|
25
|
-
# Other methods add to the :class attribute.
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
case idc
|
30
|
-
when "pass"
|
31
|
-
when /!$/
|
32
|
-
@opts[:id] = $`
|
33
|
-
else
|
34
|
-
@opts[:class] = "#{@opts[:class]} #{idc}".strip
|
35
|
-
end
|
36
|
-
if args.empty? and blk.nil?
|
37
|
-
self
|
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
|
38
29
|
else
|
30
|
+
id = id_or_class
|
31
|
+
@attrs[:class] = @attrs[:class] ? "#{@attrs[:class]} #{id}".strip : id
|
32
|
+
end
|
33
|
+
|
34
|
+
unless args.empty?
|
39
35
|
if args.last.respond_to? :to_hash
|
40
|
-
@
|
36
|
+
@attrs.merge! args.pop.to_hash
|
41
37
|
end
|
42
|
-
args.push @opts
|
43
|
-
@blk.call(args, blk)
|
44
38
|
end
|
45
|
-
end
|
46
39
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
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
51
|
|
52
|
+
self
|
53
|
+
end
|
52
54
|
end
|
53
55
|
end
|
data/lib/markaby/rails.rb
CHANGED
@@ -1,46 +1,71 @@
|
|
1
1
|
module Markaby
|
2
|
+
module Rails
|
3
|
+
UNSUPPORTED_RAILS_VERSIONS = [
|
4
|
+
"2.0.0",
|
5
|
+
"2.0.1",
|
6
|
+
"2.0.2",
|
7
|
+
"2.0.3",
|
8
|
+
"2.0.4",
|
9
|
+
"2.0.5",
|
10
|
+
"2.1.0",
|
11
|
+
"2.1.1",
|
12
|
+
"2.1.2",
|
13
|
+
"2.3.0"
|
14
|
+
]
|
2
15
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
render options.merge({ :text => Builder.new({}, self, &block).to_s })
|
11
|
-
end
|
12
|
-
end
|
16
|
+
DEPRECATED_RAILS_VERSIONS = [
|
17
|
+
"1.2.2",
|
18
|
+
"1.2.3",
|
19
|
+
"1.2.4",
|
20
|
+
"1.2.5",
|
21
|
+
"1.2.6"
|
22
|
+
]
|
13
23
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
24
|
+
FULLY_SUPPORTED_RAILS_VERSIONS = [
|
25
|
+
"2.2.0",
|
26
|
+
"2.2.1",
|
27
|
+
"2.2.2",
|
28
|
+
"2.2.3",
|
29
|
+
"2.3.1",
|
30
|
+
"2.3.2",
|
31
|
+
"2.3.2.1",
|
32
|
+
"2.3.3",
|
33
|
+
"2.3.3.1",
|
34
|
+
"2.3.4"
|
35
|
+
]
|
36
|
+
|
37
|
+
SUPPORTED_RAILS_VERSIONS = DEPRECATED_RAILS_VERSIONS + FULLY_SUPPORTED_RAILS_VERSIONS
|
22
38
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
class << self
|
40
|
+
def load
|
41
|
+
check_rails_version
|
42
|
+
|
43
|
+
if deprecated_rails_version?
|
44
|
+
require File.dirname(__FILE__) + "/rails/deprecated"
|
45
|
+
else
|
46
|
+
require File.dirname(__FILE__) + "/rails/current"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def deprecated_rails_version?
|
51
|
+
DEPRECATED_RAILS_VERSIONS.include?(detected_rails_version)
|
52
|
+
end
|
53
|
+
|
54
|
+
def check_rails_version
|
55
|
+
if UNSUPPORTED_RAILS_VERSIONS.include?(detected_rails_version)
|
56
|
+
error_message = "Cannot load markaby under rails version #{detected_rails_version}. "
|
57
|
+
error_message << "See Markaby::Rails::SUPPORTED_RAILS_VERSIONS for exactly that, or redefine this constant."
|
58
|
+
raise LoadError, error_message
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def detected_rails_version
|
65
|
+
if defined?(::Rails)
|
66
|
+
::Rails::VERSION::STRING
|
67
|
+
end
|
68
|
+
end
|
43
69
|
end
|
44
70
|
end
|
45
|
-
|
46
71
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'markaby/rails/rails_builder'
|
2
|
+
|
3
|
+
module Markaby
|
4
|
+
module Rails
|
5
|
+
class TemplateHandler < ::ActionView::TemplateHandler
|
6
|
+
include ActionView::TemplateHandlers::Compilable
|
7
|
+
|
8
|
+
def compile(template, local_assigns={})
|
9
|
+
<<-CODE
|
10
|
+
handler = Markaby::Rails::TemplateHandler.new
|
11
|
+
handler.view = self
|
12
|
+
handler.render(lambda { #{template.source} }, local_assigns)
|
13
|
+
CODE
|
14
|
+
end
|
15
|
+
|
16
|
+
def render(template, local_assigns = (template.respond_to?(:locals) ? template.locals : {}))
|
17
|
+
builder = RailsBuilder.new(instance_variables.merge(local_assigns), @view)
|
18
|
+
@view.output_buffer = builder
|
19
|
+
|
20
|
+
template.is_a?(Proc) ?
|
21
|
+
builder.instance_eval(&template) :
|
22
|
+
builder.instance_eval(template.source)
|
23
|
+
|
24
|
+
builder.to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_accessor :view
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def instance_variables
|
32
|
+
instance_variable_hash(@view)
|
33
|
+
end
|
34
|
+
|
35
|
+
def instance_variable_hash(object)
|
36
|
+
returning Hash.new do |hash|
|
37
|
+
object.instance_variables.each do |var_name|
|
38
|
+
hash[var_name.gsub("@", "")] = object.instance_variable_get(var_name)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
ActionView::Template.register_template_handler(:mab, Markaby::Rails::TemplateHandler)
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'markaby/rails/rails_builder'
|
2
|
+
|
3
|
+
module ActionView # :nodoc:
|
4
|
+
class Base # :nodoc:
|
5
|
+
def render_template(template_extension, template, file_path = nil, local_assigns = {})
|
6
|
+
if handler = @@template_handlers[template_extension]
|
7
|
+
template ||= read_template_file(file_path, template_extension)
|
8
|
+
handler.new(self).render(template, local_assigns, file_path)
|
9
|
+
else
|
10
|
+
compile_and_render_template(template_extension, template, file_path, local_assigns)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module Markaby
|
17
|
+
module Rails
|
18
|
+
class Template
|
19
|
+
|
20
|
+
def self.builder_class=(builder)
|
21
|
+
@@builder_class = builder
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.builder_class
|
25
|
+
@@builder_class ||= Builder
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_accessor :source, :path
|
29
|
+
|
30
|
+
def initialize(source)
|
31
|
+
@source = source.to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
def render(*args)
|
35
|
+
output = self.class.builder_class.new(*args)
|
36
|
+
|
37
|
+
if path
|
38
|
+
output.instance_eval source, path
|
39
|
+
else
|
40
|
+
output.instance_eval source
|
41
|
+
end
|
42
|
+
|
43
|
+
output.to_s
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Markaby helpers for Rails.
|
48
|
+
module ActionControllerHelpers
|
49
|
+
# Returns a string of HTML built from the attached +block+. Any +options+ are
|
50
|
+
# passed into the render method.
|
51
|
+
#
|
52
|
+
# Use this method in your controllers to output Markaby directly from inside.
|
53
|
+
def render_markaby(options = {}, &block)
|
54
|
+
render options.merge({ :text => Builder.new(options[:locals], self, &block).to_s })
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class ActionViewTemplateHandler # :nodoc:
|
59
|
+
def initialize(action_view)
|
60
|
+
@action_view = action_view
|
61
|
+
end
|
62
|
+
def render(template, local_assigns, file_path)
|
63
|
+
template = Template.new(template)
|
64
|
+
template.path = file_path
|
65
|
+
template.render(@action_view.assigns.merge(local_assigns), @action_view)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class Builder < RailsBuilder # :nodoc:
|
70
|
+
def initialize(*args, &block)
|
71
|
+
super *args, &block
|
72
|
+
|
73
|
+
@assigns.each { |k, v| @helpers.instance_variable_set("@#{k}", v) }
|
74
|
+
end
|
75
|
+
|
76
|
+
def flash(*args)
|
77
|
+
@helpers.controller.send(:flash, *args)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Emulate ERB to satisfy helpers like <tt>form_for</tt>.
|
81
|
+
def _erbout
|
82
|
+
@_erbout ||= FauxErbout.new(self)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Content_for will store the given block in an instance variable for later use
|
86
|
+
# in another template or in the layout.
|
87
|
+
#
|
88
|
+
# The name of the instance variable is content_for_<name> to stay consistent
|
89
|
+
# with @content_for_layout which is used by ActionView's layouts.
|
90
|
+
#
|
91
|
+
# Example:
|
92
|
+
#
|
93
|
+
# content_for("header") do
|
94
|
+
# h1 "Half Shark and Half Lion"
|
95
|
+
# end
|
96
|
+
#
|
97
|
+
# If used several times, the variable will contain all the parts concatenated.
|
98
|
+
def content_for(name, &block)
|
99
|
+
@helpers.assigns["content_for_#{name}"] =
|
100
|
+
eval("@content_for_#{name} = (@content_for_#{name} || '') + capture(&block)")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
Template.builder_class = Builder
|
105
|
+
|
106
|
+
class FauxErbout < ::Builder::BlankSlate # :nodoc:
|
107
|
+
def initialize(builder)
|
108
|
+
@builder = builder
|
109
|
+
end
|
110
|
+
def nil? # see ActionView::Helpers::CaptureHelper#capture
|
111
|
+
true
|
112
|
+
end
|
113
|
+
def method_missing(*args, &block)
|
114
|
+
@builder.send *args, &block
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
if defined? ActionView::Template and ActionView::Template.respond_to? :register_template_handler
|
120
|
+
ActionView::Template
|
121
|
+
else
|
122
|
+
ActionView::Base
|
123
|
+
end.register_template_handler(:mab, Markaby::Rails::ActionViewTemplateHandler)
|
124
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Markaby
|
2
|
+
module Rails
|
3
|
+
class RailsBuilder < Markaby::Builder
|
4
|
+
def form_for(*args, &block)
|
5
|
+
@template.form_for(*args) do |__form_for_variable|
|
6
|
+
yield(FormHelperProxy.new(self, __form_for_variable))
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# This is used for the block variable given to form_for. Typically, an erb template looks as so:
|
11
|
+
#
|
12
|
+
# <% form_for :foo do |f|
|
13
|
+
# <%= f.text_field :bar %>
|
14
|
+
# <% end %>
|
15
|
+
#
|
16
|
+
# form_for adds the form tag to the input stream, and assumes that later the user will append
|
17
|
+
# the <input> tag to the input stream himself (in erb, this is done with the <%= %> tags).
|
18
|
+
#
|
19
|
+
# We could do the following in Markaby:
|
20
|
+
#
|
21
|
+
# form_for :foo do |f|
|
22
|
+
# text f.text_field(:bar)
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# But this is ugly. This is prettier:
|
26
|
+
#
|
27
|
+
# form_for :foo do |f|
|
28
|
+
# f.text_field :bar
|
29
|
+
# end
|
30
|
+
class FormHelperProxy
|
31
|
+
def initialize(builder, proxied_object)
|
32
|
+
@builder = builder
|
33
|
+
@proxied_object = proxied_object
|
34
|
+
end
|
35
|
+
|
36
|
+
def respond_to?(sym, include_private = false)
|
37
|
+
@proxied_object.respond_to?(sym, include_private) || super
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def method_missing(sym, *args, &block)
|
43
|
+
result = @proxied_object.__send__(sym, *args, &block)
|
44
|
+
@builder.text(result) if result.is_a?(String)
|
45
|
+
result
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|