mab 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data/COPYING +19 -0
  2. data/Gemfile +10 -0
  3. data/Gemfile.lock +12 -0
  4. data/README.md +224 -0
  5. data/Rakefile +8 -0
  6. data/bench.rb +37 -0
  7. data/lib/mab/mixin.rb +58 -42
  8. data/lib/mab/version.rb +1 -1
  9. data/mab-0.0.1.gem +0 -0
  10. data/mab.gemspec +20 -0
  11. data/markaby/CHANGELOG.rdoc +106 -0
  12. data/markaby/Markaby.gemspec +109 -0
  13. data/markaby/README.rdoc +317 -0
  14. data/markaby/Rakefile +78 -0
  15. data/markaby/VERSION +1 -0
  16. data/markaby/garlic.rb +29 -0
  17. data/markaby/init.rb +6 -0
  18. data/markaby/lib/markaby.rb +30 -0
  19. data/markaby/lib/markaby/builder.rb +314 -0
  20. data/markaby/lib/markaby/builder_tags.rb +64 -0
  21. data/markaby/lib/markaby/cssproxy.rb +55 -0
  22. data/markaby/lib/markaby/kernel_method.rb +7 -0
  23. data/markaby/lib/markaby/rails.rb +75 -0
  24. data/markaby/lib/markaby/rails/current.rb +85 -0
  25. data/markaby/lib/markaby/rails/deprecated.rb +124 -0
  26. data/markaby/lib/markaby/rails/rails_builder.rb +91 -0
  27. data/markaby/lib/markaby/sinatra.rb +18 -0
  28. data/markaby/lib/markaby/tags.rb +200 -0
  29. data/markaby/lib/markaby/tilt.rb +8 -0
  30. data/markaby/spec/markaby/builder_spec.rb +118 -0
  31. data/markaby/spec/markaby/css_proxy_test.rb +47 -0
  32. data/markaby/spec/markaby/fragment_test.rb +10 -0
  33. data/markaby/spec/markaby/markaby_other_static.mab +1 -0
  34. data/markaby/spec/markaby/markaby_spec.rb +184 -0
  35. data/markaby/spec/markaby/markaby_test.rb +251 -0
  36. data/markaby/spec/markaby/rails/spec_helper.rb +29 -0
  37. data/markaby/spec/markaby/rails/views/layouts/layout.mab +11 -0
  38. data/markaby/spec/markaby/rails/views/markaby/_a_partial.mab +3 -0
  39. data/markaby/spec/markaby/rails/views/markaby/_form_for_with_body_in_erb.erb +1 -0
  40. data/markaby/spec/markaby/rails/views/markaby/_partial_child_with_locals.mab +1 -0
  41. data/markaby/spec/markaby/rails/views/markaby/access_to_helpers.mab +1 -0
  42. data/markaby/spec/markaby/rails/views/markaby/broken.mab +7 -0
  43. data/markaby/spec/markaby/rails/views/markaby/commented_out_template.mab +1 -0
  44. data/markaby/spec/markaby/rails/views/markaby/correct_template_values.mab +5 -0
  45. data/markaby/spec/markaby/rails/views/markaby/double_output.mab +8 -0
  46. data/markaby/spec/markaby/rails/views/markaby/form_for.mab +2 -0
  47. data/markaby/spec/markaby/rails/views/markaby/form_for_with_fields.mab +3 -0
  48. data/markaby/spec/markaby/rails/views/markaby/form_for_with_multiple_fields.mab +4 -0
  49. data/markaby/spec/markaby/rails/views/markaby/no_values_passed.mab +3 -0
  50. data/markaby/spec/markaby/rails/views/markaby/partial_parent.mab +1 -0
  51. data/markaby/spec/markaby/rails/views/markaby/partial_parent_with_locals.mab +7 -0
  52. data/markaby/spec/markaby/rails/views/markaby/render_erb_without_explicit_render_call.erb +1 -0
  53. data/markaby/spec/markaby/rails/views/markaby/render_explicit_but_empty_markaby_layout.mab +0 -0
  54. data/markaby/spec/markaby/rails/views/markaby/render_mab_without_explicit_render_call.mab +3 -0
  55. data/markaby/spec/markaby/rails/views/markaby/render_with_ivar.mab +3 -0
  56. data/markaby/spec/markaby/rails/views/markaby/renders_erb.rhtml +1 -0
  57. data/markaby/spec/markaby/rails/views/markaby/renders_form_for_with_erb_body.mab +3 -0
  58. data/markaby/spec/markaby/rails/views/markaby/routes.mab +1 -0
  59. data/markaby/spec/markaby/rails/views/markaby/yielding.mab +3 -0
  60. data/markaby/spec/markaby/rails/views/markaby/yielding_content_for_with_block_helper.mab +5 -0
  61. data/markaby/spec/markaby/rails/views/markaby/yielding_two.mab +7 -0
  62. data/markaby/spec/markaby/rails/views/markaby/yielding_with_content_for.mab +3 -0
  63. data/markaby/spec/markaby/rails_test.rb +380 -0
  64. data/markaby/spec/markaby/rails_version_spec.rb +37 -0
  65. data/markaby/spec/markaby/sinatra/app.rb +49 -0
  66. data/markaby/spec/markaby/sinatra/sinatra_spec.rb +67 -0
  67. data/markaby/spec/markaby/sinatra/views/helpers.mab +1 -0
  68. data/markaby/spec/markaby/sinatra/views/layout.mab +7 -0
  69. data/markaby/spec/markaby/sinatra/views/markaby_template.mab +0 -0
  70. data/markaby/spec/markaby/sinatra/views/scope_instance_variables.mab +3 -0
  71. data/markaby/spec/markaby/sinatra/views/simple_html.mab +4 -0
  72. data/markaby/spec/markaby/sinatra/views/variables.mab +3 -0
  73. data/markaby/spec/markaby/tilt/erb.erb +1 -0
  74. data/markaby/spec/markaby/tilt/locals.mab +1 -0
  75. data/markaby/spec/markaby/tilt/markaby.mab +1 -0
  76. data/markaby/spec/markaby/tilt/markaby_other_static.mab +1 -0
  77. data/markaby/spec/markaby/tilt/render_twice.mab +1 -0
  78. data/markaby/spec/markaby/tilt/scope.mab +1 -0
  79. data/markaby/spec/markaby/tilt/yielding.mab +2 -0
  80. data/markaby/spec/markaby/tilt_spec.rb +75 -0
  81. data/markaby/spec/spec.opts +2 -0
  82. data/markaby/spec/spec_helper.rb +44 -0
  83. data/test/helper.rb +4 -0
  84. data/test/test_mab_builder.rb +56 -0
  85. data/test/test_mab_indentation.rb +66 -0
  86. data/test/test_mab_kernel_method.rb +10 -0
  87. data/test/test_mab_mixin.rb +246 -0
  88. metadata +92 -6
@@ -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.map { |m| m.to_sym }.include?(sym.to_sym) ? 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,7 @@
1
+ # You'll need to <tt>require 'markaby/kernel_method'</tt> for this.
2
+ module Kernel
3
+ # Shortcut for creating a quick block of Markaby.
4
+ def mab(*args, &block)
5
+ Markaby::Builder.new(*args, &block).to_s
6
+ end
7
+ end
@@ -0,0 +1,75 @@
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
+ ]
15
+
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
+ ]
23
+
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
+ "2.3.5",
36
+ "2.3.6",
37
+ "2.3.7",
38
+ "2.3.8"
39
+ ]
40
+
41
+ SUPPORTED_RAILS_VERSIONS = DEPRECATED_RAILS_VERSIONS + FULLY_SUPPORTED_RAILS_VERSIONS
42
+
43
+ class << self
44
+ def load
45
+ check_rails_version
46
+
47
+ if deprecated_rails_version?
48
+ require File.dirname(__FILE__) + "/rails/deprecated"
49
+ else
50
+ require File.dirname(__FILE__) + "/rails/current"
51
+ end
52
+ end
53
+
54
+ def deprecated_rails_version?
55
+ DEPRECATED_RAILS_VERSIONS.include?(detected_rails_version)
56
+ end
57
+
58
+ def check_rails_version
59
+ if UNSUPPORTED_RAILS_VERSIONS.include?(detected_rails_version)
60
+ error_message = "Cannot load markaby under rails version #{detected_rails_version}. "
61
+ error_message << "See Markaby::Rails::SUPPORTED_RAILS_VERSIONS for exactly that, or redefine this constant."
62
+ raise LoadError, error_message
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ def detected_rails_version
69
+ if defined?(::Rails)
70
+ ::Rails::VERSION::STRING
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,85 @@
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
+ __template_handler = Markaby::Rails::TemplateHandler.new
11
+ __template_handler.view = self
12
+ __template_handler.render(lambda {
13
+ #{template.source}
14
+ }, local_assigns)
15
+ CODE
16
+ end
17
+
18
+ def render(template, local_assigns = (template.respond_to?(:locals) ? template.locals : {}))
19
+ builder = RailsBuilder.new(instance_variables.merge(local_assigns), @view)
20
+ @view.output_buffer = builder
21
+
22
+ template.is_a?(Proc) ?
23
+ builder.instance_eval(&template) :
24
+ builder.instance_eval(template.source)
25
+
26
+ builder.to_s
27
+ end
28
+
29
+ attr_accessor :view
30
+
31
+ private
32
+
33
+ def instance_variables
34
+ instance_variable_hash(@view)
35
+ end
36
+
37
+ def instance_variable_hash(object)
38
+ returning Hash.new do |hash|
39
+ object.instance_variables.each do |var_name|
40
+ hash[var_name.gsub("@", "")] = object.instance_variable_get(var_name)
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ module Helpers
47
+ # allow fragments to act as strings. url_for has a
48
+ # case statment in it:
49
+ #
50
+ # case options
51
+ # when String
52
+ # ...
53
+ #
54
+ # which essential is doing the following:
55
+ #
56
+ # String === options
57
+ #
58
+ # That assertion fails with Markaby::Fragments, which are essential
59
+ # builder/string fragments.
60
+ #
61
+ def url_for(options={})
62
+ case options
63
+ when Markaby::Fragment
64
+ super(options.to_s)
65
+ else
66
+ super
67
+ end
68
+ end
69
+
70
+ def capture(*args, &block)
71
+ if output_buffer.kind_of?(Markaby::Builder)
72
+ output_buffer.capture(&block)
73
+ else
74
+ super
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ ActionView::Base.class_eval do
82
+ include Markaby::Rails::Helpers
83
+ end
84
+
85
+ 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,91 @@
1
+ module Markaby
2
+ module Rails
3
+ class RailsBuilder < Markaby::Builder
4
+ def form_for(*args, &block)
5
+ @_helper.output_buffer = OutputBuffer.new
6
+
7
+ @template.form_for(*args) do |__form_for_variable|
8
+ # flush <form tags> + switch back to markaby
9
+ text(@_helper.output_buffer)
10
+ @_helper.output_buffer = self
11
+
12
+ yield FormHelperProxy.new(@_helper, __form_for_variable)
13
+
14
+ # switch back to output string output buffer and flush
15
+ # final </form> tag
16
+ @_helper.output_buffer = OutputBuffer.new
17
+ end
18
+ text(@_helper.output_buffer)
19
+
20
+ # finally, switch back to our regular buffer
21
+ @_helper.output_buffer = self
22
+ end
23
+
24
+ alias_method :safe_concat, :concat
25
+
26
+ # Rails 2.3.6 calls safe_concat on the output buffer.
27
+ # Future versions of rails alias safe_concat to concat on the core
28
+ # class String.
29
+ #
30
+ # Obviously, that's a bad idea. Thanks a ton, Rails.
31
+ class OutputBuffer < String
32
+ alias_method :safe_concat, :concat
33
+ end
34
+
35
+ # This is used for the block variable given to form_for. Typically, an erb template looks as so:
36
+ #
37
+ # <% form_for :foo do |f|
38
+ # <%= f.text_field :bar %>
39
+ # <% end %>
40
+ #
41
+ # form_for adds the form tag to the input stream, and assumes that later the user will append
42
+ # the <input> tag to the input stream himself (in erb, this is done with the <%= %> tags).
43
+ #
44
+ # We could do the following in Markaby:
45
+ #
46
+ # form_for :foo do |f|
47
+ # text f.text_field(:bar)
48
+ # end
49
+ #
50
+ # But this is ugly. This is prettier:
51
+ #
52
+ # form_for :foo do |f|
53
+ # f.text_field :bar
54
+ # end
55
+ class FormHelperProxy
56
+ def initialize(view, proxied_object)
57
+ @view = view
58
+ @proxied_object = proxied_object
59
+ end
60
+
61
+ def respond_to?(sym, include_private = false)
62
+ @proxied_object.respond_to?(sym, include_private) || super
63
+ end
64
+
65
+ private
66
+
67
+ if ::Rails::VERSION::STRING == "2.2.0"
68
+ def __template__
69
+ @view.instance_variable_get("@_last_render")
70
+ end
71
+ else
72
+ def __template__
73
+ @view.template
74
+ end
75
+ end
76
+
77
+ def method_missing(sym, *args, &block)
78
+ result = @proxied_object.__send__(sym, *args, &block)
79
+
80
+ # a markaby template may call render :partial with the form proxy helper.
81
+ # we only want to manually concat _if_ we are in a markaby template (not, say, erb)
82
+ if __template__.extension == "mab"
83
+ @view.concat(result)
84
+ end
85
+
86
+ result
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end