hobo 0.8.5 → 0.8.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/CHANGES.txt +41 -0
  2. data/Manifest +1 -5
  3. data/Rakefile +10 -3
  4. data/bin/hobo +38 -15
  5. data/dryml_generators/rapid/cards.dryml.erb +7 -7
  6. data/dryml_generators/rapid/pages.dryml.erb +52 -24
  7. data/hobo.gemspec +42 -322
  8. data/init.rb +0 -7
  9. data/lib/active_record/association_collection.rb +9 -0
  10. data/lib/hobo.rb +13 -14
  11. data/lib/hobo/accessible_associations.rb +32 -7
  12. data/lib/hobo/authentication_support.rb +1 -1
  13. data/lib/hobo/controller.rb +5 -7
  14. data/lib/hobo/dryml.rb +9 -2
  15. data/lib/hobo/dryml/dryml_builder.rb +11 -12
  16. data/lib/hobo/dryml/dryml_doc.rb +22 -24
  17. data/lib/hobo/dryml/dryml_generator.rb +41 -4
  18. data/lib/hobo/dryml/part_context.rb +5 -3
  19. data/lib/hobo/dryml/template.rb +7 -7
  20. data/lib/hobo/dryml/template_environment.rb +11 -22
  21. data/lib/hobo/dryml/template_handler.rb +94 -25
  22. data/lib/hobo/find_for.rb +2 -2
  23. data/lib/hobo/hobo_helper.rb +21 -21
  24. data/lib/hobo/include_in_save.rb +9 -5
  25. data/lib/hobo/lifecycles/transition.rb +2 -2
  26. data/lib/hobo/model.rb +11 -61
  27. data/lib/hobo/model_controller.rb +28 -29
  28. data/lib/hobo/model_router.rb +12 -13
  29. data/lib/hobo/permissions.rb +47 -37
  30. data/lib/hobo/permissions/associations.rb +1 -1
  31. data/lib/hobo/scopes/association_proxy_extensions.rb +5 -6
  32. data/lib/hobo/scopes/automatic_scopes.rb +7 -4
  33. data/lib/hobo/tasks/rails.rb +4 -0
  34. data/lib/hobo/user.rb +0 -1
  35. data/lib/hobo/user_controller.rb +3 -1
  36. data/lib/hobo/view_hints.rb +17 -3
  37. data/rails_generators/hobo/hobo_generator.rb +1 -0
  38. data/rails_generators/hobo_front_controller/templates/functional_test.rb +1 -11
  39. data/rails_generators/hobo_front_controller/templates/index.dryml +1 -6
  40. data/rails_generators/hobo_rapid/hobo_rapid_generator.rb +1 -0
  41. data/rails_generators/hobo_rapid/templates/hobo-rapid.css +3 -2
  42. data/rails_generators/hobo_rapid/templates/hobo-rapid.js +24 -15
  43. data/rails_generators/hobo_rapid/templates/themes/clean/public/stylesheets/clean.css +17 -12
  44. data/rails_generators/hobo_rapid/templates/themes/clean/public/stylesheets/rapid-ui.css +6 -2
  45. data/rails_generators/hobo_rapid/templates/themes/clean/views/clean.dryml +2 -2
  46. data/rails_generators/hobo_user_model/templates/forgot_password.erb +2 -2
  47. data/rails_generators/hobo_user_model/templates/model.rb +2 -2
  48. data/taglibs/rapid.dryml +3 -2
  49. data/taglibs/rapid_core.dryml +21 -16
  50. data/taglibs/rapid_document_tags.dryml +1 -1
  51. data/taglibs/rapid_editing.dryml +7 -10
  52. data/taglibs/rapid_forms.dryml +115 -26
  53. data/taglibs/rapid_generics.dryml +13 -3
  54. data/taglibs/rapid_lifecycles.dryml +18 -1
  55. data/taglibs/rapid_navigation.dryml +50 -61
  56. data/taglibs/rapid_pages.dryml +103 -19
  57. data/taglibs/rapid_plus.dryml +54 -6
  58. data/taglibs/rapid_support.dryml +38 -1
  59. data/taglibs/rapid_user_pages.dryml +17 -5
  60. data/test/permissions/models/models.rb +24 -12
  61. data/test/permissions/models/test.sqlite3 +0 -0
  62. metadata +6 -15
  63. data/lib/extensions/test_case.rb +0 -129
  64. data/lib/hobo/composite_model.rb +0 -73
  65. data/lib/hobo/model_support.rb +0 -44
  66. data/tasks/fix_dryml.rake +0 -143
  67. data/tasks/generate_tag_reference.rake +0 -192
  68. data/test/dryml/complilation_test.rb +0 -261
@@ -1,44 +0,0 @@
1
- module Hobo
2
-
3
- module ModelSupport
4
-
5
- # This module provides methods common to both Hobo::Model and Hobo::CompositeModel
6
-
7
- def self.included(base)
8
- base.extend(ClassMethods) if base.is_a? Class
9
- end
10
-
11
- module ClassMethods
12
-
13
- def delegate_and_compose(*methods)
14
- options = methods.pop
15
- unless options.is_a?(Hash) && to = options[:to]
16
- raise ArgumentError, ("Delegation needs a target. Supply an options hash " +
17
- "with a :to key as the last argument (e.g. delegate :hello, :to => :greeter).")
18
- end
19
- use = options[:use]
20
-
21
- methods.each do |method|
22
- module_eval(<<-EOS, "(__COMPOSED_DELEGATION__)", 1)
23
- def #{method}
24
- @__#{method}_result__ ||= begin
25
- obj = #{to}.__send__(#{method.inspect})
26
- return nil if obj.nil?
27
-
28
- if obj.nil?
29
- nil
30
- elsif obj.is_a?(Array)
31
- obj.map {|o| self.compose_with(o, #{use.inspect})}
32
- else
33
- self.compose_with(obj, #{use.inspect})
34
- end
35
- end
36
- end
37
- EOS
38
- end
39
- end
40
-
41
- end
42
-
43
- end
44
- end
@@ -1,143 +0,0 @@
1
- require 'fileutils'
2
-
3
- def restore_erb_scriptlets(scriptlets, src)
4
- src.gsub(/\[!\[HOBO-ERB(\d+)\s*\]!\]/m) {|s| "<%#{scriptlets[$1.to_i]}%>" }
5
- end
6
-
7
-
8
- def fix_nodes(nodes)
9
- nodes.map{|x| fix_element(x) if x.is_a?(REXML::Element) }
10
- end
11
-
12
-
13
- def start_tag_replace(el, repl)
14
- i, len = el.source_offset, el.start_tag_source.length
15
- @src[i..i+len-1] = repl
16
- end
17
-
18
-
19
- def classes?
20
- ENV['CLASS']
21
- end
22
-
23
- def ids?
24
- ENV['ID']
25
- end
26
-
27
-
28
- def string_interpolate_safe_dasherize(s)
29
- token = "[[MAKE_ME_A_DASH!]]"
30
- s.gsub("_", token).
31
- gsub(/\#\{.*?\}/) {|s2| s2.gsub(token, "_") }.
32
- gsub(token, "-")
33
- end
34
-
35
-
36
- def fix_children(element, template_params)
37
- element.elements.to_a.reverse.each do |e|
38
- # recurse first - we're going backwards
39
- is_template_call = e.dryml_name =~ /^[A-Z]/ && !e.attribute("replace")
40
- fix_children(e, is_template_call)
41
-
42
- fixed = fix_element(e, template_params)
43
- start_tag_replace(e, fixed)
44
- end
45
- end
46
-
47
-
48
- def fix_element(e, template_param)
49
- tag = e.start_tag_source.dup
50
-
51
- if e.dryml_name == "tagbody"
52
- tag.sub!("<tagbody", '<do param="default"')
53
- elsif e.dryml_name == "default_tagbody"
54
- tag.sub!("<default_tagbody", '<param-content')
55
- else
56
- tag.sub!("<#{e.dryml_name}", "<#{e.dryml_name.underscore.dasherize}#{':' if template_param}")
57
- end
58
-
59
- start = e.expanded_name.length+1
60
- tag[start..-1] = tag[start..-1].gsub(/([A-Za-z_]+)(\s*=\s*("(.*?)"|'(.*?)'))?/) do |s|
61
- _, name, _, value = *Regexp.last_match
62
-
63
- s.sub!(/^#{name}/, name.dasherize)
64
-
65
- if value
66
- # underscore / dasherize the values of various attributes
67
-
68
- if e.name == "def" && name.in?(%w(tag attrs alias_of extend_with))
69
- s.sub!(/#{Regexp.escape(value)}$/) {|v| v.underscore.dasherize}
70
-
71
- elsif name.in?(%w(part update)) || (classes? && name == 'class') || (ids? && name == 'id')
72
- s.sub!(/#{Regexp.escape(value)}$/) {|v| string_interpolate_safe_dasherize(v) }
73
-
74
- elsif name == "param"
75
- s.sub!(/#{Regexp.escape(value)}$/) {|v| string_interpolate_safe_dasherize(v.underscore) }
76
- end
77
-
78
- end
79
- s
80
- end
81
- tag
82
- end
83
-
84
-
85
- def fix_file(filename)
86
- puts "Fixing #{filename}"
87
- src = File.read(filename)
88
-
89
- # Ripped from Hobo::Dryml::Template - hide erb scriptlets and parse with REXML
90
- scriptlets = {}
91
- src = src.gsub(/<%(.*?)%>/m) do
92
- _, scriptlet = *Regexp.last_match
93
- id = scriptlets.size + 1
94
- scriptlets[id] = scriptlet
95
- newlines = "\n" * scriptlet.count("\n")
96
- "[![HOBO-ERB#{id}#{newlines}]!]"
97
- end
98
-
99
- # DRYML doesn't have to have a single root - add one to keep REXML
100
- # happy
101
- @src = "<root>" + src + "</root>"
102
- begin
103
- doc = Hobo::Dryml::Parser::Document.new(Hobo::Dryml::Parser::Source.new(@src))
104
- rescue REXML::ParseException => e
105
- raise Exception, "File: #{@template_path}\n#{e}"
106
- end
107
-
108
- fix_children(doc[0], false)
109
-
110
- #Fix close tags
111
- @src.gsub!(/<\/[^:>]*/) { |s| s.underscore.dasherize }
112
- @src.gsub!(/<\/tagbody\s*>/, "</do>")
113
-
114
- # Strip the root tag we added
115
- @src.sub!(/^<root>/, "")
116
- @src.sub!(/<\/root>$/, "")
117
-
118
- fixed = restore_erb_scriptlets(scriptlets, @src)
119
- File.open(filename, 'w') { |f| f.write(fixed) }
120
- end
121
-
122
-
123
- namespace :hobo do
124
-
125
- desc "Replace old-style DRYML source code with CamelCaseTags and underscores with new DRYML syntax"
126
- task :fixdryml => :environment do
127
-
128
- dir = ENV['DIR']._?.sub(/\/$/, '') || "app/views"
129
-
130
- # Make a backup
131
- backup_dir = "#{dir.gsub('../', '').gsub('/', '_')}_before_fixdryml"
132
- if File.exist?(backup_dir)
133
- puts "Backup (#{backup_dir}) already exists - be careful! (nothing changed)"
134
- exit
135
- end
136
- FileUtils.cp_r(dir, backup_dir)
137
-
138
- Dir["#{dir}/**/*.dryml"].each do |f|
139
- fix_file(f)
140
- end
141
- end
142
-
143
- end
@@ -1,192 +0,0 @@
1
- require 'fileutils'
2
-
3
- ActiveSupport::Dependencies.load_paths << File.dirname(__FILE__) + "/../lib"
4
-
5
- require 'rexml/xpath'
6
- XPath = REXML::XPath
7
-
8
- def tag_title(tag, link=false)
9
- if tag.is_a? String
10
- name = tag
11
- anchor = tag
12
- else
13
- for_attr = tag.attributes['for'] and for_decl = %( for=`"#{for_attr}"`)
14
- name = tag.attributes['tag']
15
- anchor = tag_anchor(tag)
16
- end
17
-
18
- title = "&lt;#{name}#{for_decl}&gt;"
19
-
20
- if link
21
- "[#{title}](##{anchor})"
22
- else
23
- title
24
- end
25
- end
26
-
27
-
28
- def link_to_tag(tag)
29
- tag_title(tag, true)
30
- end
31
-
32
-
33
- def tag_anchor(element)
34
- for_attr = element.attributes['for']
35
- name = element.attributes['tag']
36
-
37
- if for_attr
38
- "#{name}--for-#{for_attr}"
39
- else
40
- name
41
- end
42
- end
43
-
44
-
45
- def comment_for_tag(element)
46
- space = element.previous_sibling and
47
- space.to_s.blank? && space.to_s.count("\n") == 1 and
48
- comment = space.previous_sibling
49
-
50
- comment.to_s.strip if comment.is_a?(REXML::Comment)
51
- end
52
-
53
-
54
- def doc_for_tag(tagdef)
55
- comment = comment_for_tag(tagdef)
56
-
57
- params_merged_with = XPath.first(tagdef, ".//*[@merge|@merge-params]")._?.name
58
- params_merged_with &&= "(merged with #{link_to_tag params_merged_with})"
59
-
60
- attrs_merged_with = XPath.first(tagdef, ".//*[@merge|@merge-attrs]")._?.name
61
- attrs_merged_with &&= "(merged with #{link_to_tag attrs_merged_with})"
62
-
63
- attrs = tagdef.attributes['attrs'] || []
64
- attrs = attrs.split(/,\s*/).where_not.blank?.map { |a| " * #{a}\n" }.join
65
-
66
- parameters = params_to_list(get_parameters(tagdef))
67
- <<-END
68
- ---
69
-
70
- <a name="#{tag_anchor tagdef}">&nbsp;</a>
71
- ## #{tag_title tagdef}
72
-
73
- #{comment}
74
-
75
- ### Attributes #{attrs_merged_with}
76
-
77
- #{attrs.blank? ? 'None' : attrs}
78
-
79
- ### Parameters #{params_merged_with}
80
-
81
- #{parameters.blank? ? 'None' : parameters}
82
- END
83
- end
84
-
85
-
86
- def get_parameters(elem)
87
- result = []
88
- elem.elements.each do |e|
89
- if e.attributes['param']
90
- result << [e, get_parameters(e)]
91
- else
92
- result.concat(get_parameters(e))
93
- end
94
- end
95
- result
96
- end
97
-
98
-
99
- def params_to_list(params, indent=" ")
100
- items = params.map do |elem, sub_params|
101
- p_attr = elem.attributes['param']
102
- entry = if p_attr == "&true"
103
- "&lt;#{elem.name}:&gt;"
104
- elsif p_attr =~ /#\{/
105
- "(dynamic parameter) (&lt;#{elem.name}&gt;)"
106
- else
107
- "&lt;#{p_attr}:&gt; (&lt;#{elem.name}&gt;)"
108
- end
109
- sub_list = params_to_list(sub_params, indent + ' ') unless sub_params.empty?
110
- "<li>#{entry}\n#{sub_list}</li>\n"
111
- end.join
112
-
113
- items.any? ? "<ul>#{items}</ul>" : ""
114
- end
115
-
116
-
117
- def contents(root)
118
- tags = XPath.match(root, '/*/*[@tag]')
119
- tags.map { |tag| " * #{link_to_tag tag}\n" }.join
120
- end
121
-
122
-
123
- def doc_for_taglib(title, root)
124
- tags = XPath.match(root, '/*/*[@tag]').map { |e| doc_for_tag(e) }.join("\n\n")
125
-
126
- "# #{title}\n\n" + contents(root) + "\n\n" + tags
127
- end
128
-
129
- def index_page(output_files, output_dir)
130
- markdown = "# Tag Documentation\n\n" + output_files.map do |f|
131
- link = f.gsub(output_dir+'/', '')
132
- link_text = link.gsub('_', '\_').gsub(/\.html$/, '')
133
- "* [#{link_text}](#{link})"
134
- end.join("\n")
135
-
136
- html = Maruku.new(markdown).to_html
137
-
138
- File.open("#{output_dir}/index.html", 'w') { |f| f.write(html) }
139
- end
140
-
141
- def process_directory(src, output_dir, output_format)
142
- raise RuntimeError, "#{output_dir} is not a directory" if File.exists?(output_dir) && !File.directory?(output_dir)
143
-
144
- FileUtils.mkdir output_dir unless File.exists? output_dir
145
-
146
- dryml_files = File.directory?(src) ? Dir["#{src}/*"] : [src]
147
-
148
- output_files = []
149
-
150
- dryml_files.each do |f|
151
- if File.directory?(f)
152
- output_files += process_directory(f, "#{output_dir}/#{File.basename(f)}", output_format)
153
- elsif f =~ /\.dryml$/
154
- basename = File.basename(f).sub(/\.dryml$/, '')
155
- title = basename.titleize
156
-
157
- doc = Hobo::Dryml::Parser::Document.new(File.read(f), f)
158
-
159
- output = doc.restore_erb_scriptlets(doc_for_taglib(title, doc))
160
- output = Maruku.new(output).to_html.gsub('&amp;', '&') if output_format == 'html'
161
-
162
- output_file = "#{output_dir}/#{basename}.#{output_format}"
163
- puts output_file
164
- File.open(output_file, 'w') { |f| f.write(output) }
165
- output_files << output_file
166
- end
167
- end
168
- output_files
169
- end
170
-
171
-
172
-
173
- namespace :hobo do
174
-
175
- desc "Generate markdown formatted reference docs automatically from DRYML taglibs"
176
- task :generate_tag_reference => :environment do
177
- gem 'maruku'
178
- require 'maruku'
179
-
180
- src = ENV['src']
181
-
182
- output_dir = ENV['output'] || "taglib-docs"
183
-
184
- output_format = ENV['format'] || "markdown"
185
-
186
- output_files = process_directory(src, output_dir, output_format)
187
-
188
- index_page(output_files, output_dir)
189
- end
190
-
191
- end
192
-
@@ -1,261 +0,0 @@
1
- require "#{File.dirname __FILE__}/dryml_test_case"
2
-
3
- class CompilationTest < DrymlTestCase
4
-
5
- should "compile tag calls as method calls" do
6
- assert_compiles_to "<% _output(foo.to_s) %>", "<foo/>"
7
- end
8
-
9
- should "convert dashes in tag names to underscores in compiled method calls" do
10
- assert_compiles_to "<% _output(foo_baa.to_s) %>", "<foo-baa/>"
11
- end
12
-
13
- should "compile attributes as keyword parameters" do
14
- assert_compiles_to '<% _output(foo({:a => "1", :b => "2"}, {})) %>', "<foo a='1' b='2'/>"
15
- end
16
-
17
- should "convert attribute names with dashes in tag calls to symbols with underscores" do
18
- assert_compiles_to "<% _output(foo({:my_attribute => \"1\"}, {})) %>", "<foo my-attribute='1'/>"
19
- end
20
-
21
- should "compile code attributes as ruby code" do
22
- assert_compiles_to '<% _output(foo({:a => (1 + 2)}, {})) %>', "<foo a='&1 + 2'/>"
23
- end
24
-
25
- should "compile attributes with no RHS as passing `true`" do
26
- assert_compiles_to '<% _output(foo({:a => (true)}, {})) %>', "<foo a/>"
27
- end
28
-
29
- should "compile content of a tag call as the default parameter" do
30
- assert_compiles_to "<% _output(foo({}, { :default => proc { |_foo__default_content| new_context { %>the body<% } }, })) %>",
31
- "<foo>the body</foo>"
32
- end
33
-
34
- should "support <param_content/> inside the content of a tag" do
35
- src = "<foo>!!<param-content/>??</foo>"
36
- assert_compiles_to "<% _output(foo({}, { :default => proc { |_foo__default_content| new_context { %>!!<%= _foo__default_content && _foo__default_content.call %>??<% } }, })) %>", src
37
- end
38
-
39
- should "support the 'for' attribute on <param-content/>" do
40
- src = "<x><y>123<param-content for='x'/>456</y></x>"
41
- assert_compiles_to(
42
- "<% _output(x({}, { :default => proc { |_x__default_content| new_context { %><% _output(y({}, { :default => proc { |_y__default_content| new_context { %>" +
43
- "123<%= _x__default_content && _x__default_content.call %>456" +
44
- "<% } }, })) %><% } }, })) %>", src)
45
- end
46
-
47
- should "allow :foo as a shorthand for field='foo' on tags" do
48
- assert_compiles_to '<% _output(foo({:field => "name"}, {})) %>', "<foo:name/>"
49
- end
50
-
51
- should "allow static tag names like :title as a shorthand for field='title'" do
52
- assert_compiles_to '<% _output(foo({:field => "name"}, {})) %>', "<foo:name/>"
53
- end
54
-
55
- should "allow close tags to ommit the :field_name part" do
56
- assert_compiles_to '<% _output(foo({:field => "name"}, { :default => proc { |_foo__default_content| new_context { %><% } }, })) %>', "<foo:name></foo>"
57
-
58
- end
59
-
60
- should "compile tag calls with merge-attrs" do
61
- assert_compiles_to "<% _output(foo(merge_attrs({},(attributes) || {}), {})) %>", "<foo merge-attrs/>"
62
- assert_compiles_to '<% _output(foo(merge_attrs({:a => "1"},(attributes) || {}), {})) %>', "<foo a='1' merge-attrs/>"
63
- end
64
-
65
-
66
- # --- Compilation: Defining Tags --- #
67
-
68
- should "compile defs" do
69
- assert_compiles_to(
70
- "<% def foo(all_attributes={}, all_parameters={}); " +
71
- "parameters = Hobo::Dryml::TagParameters.new(all_parameters, []); " +
72
- "all_parameters = Hobo::Dryml::TagParameters.new(all_parameters); " +
73
- "_tag_context(all_attributes) do attributes, = _tag_locals(all_attributes, []) %>" +
74
- "<% _erbout; end; end %>",
75
-
76
- "<def tag='foo'></def>")
77
-
78
- end
79
-
80
- should "compile attrs in defs as local variables" do
81
- assert_compiles_to(
82
- "<% def foo(all_attributes={}, all_parameters={}); " +
83
- "parameters = Hobo::Dryml::TagParameters.new(all_parameters, []); " +
84
- "all_parameters = Hobo::Dryml::TagParameters.new(all_parameters); " +
85
- "_tag_context(all_attributes) do " +
86
- "a, my_attr, attributes, = _tag_locals(all_attributes, [:a, :my_attr]) %>" +
87
- "<% _erbout; end; end %>",
88
-
89
- "<def tag='foo' attrs='a, my-attr'></def>")
90
- end
91
-
92
- should "dissallow `param` outside of tag definitions" do
93
- assert_raise(DrymlException) { compile_dryml("<foo param/>") }
94
- end
95
-
96
- should "compile param-tag calls as calls to `call_tag_parameter`" do
97
- assert_compiles_to '<% _output(call_tag_parameter(:foo, {:a => "1"}, {}, all_parameters, :foo)) %>',
98
- "<foo param a='1'/>",
99
- :in_def
100
- end
101
-
102
- should "compile with support for named params" do
103
- assert_compiles_to "<% _output(call_tag_parameter(:foo, {}, {}, all_parameters, :zap)) %>", "<foo param='zap'/>", :in_def
104
- end
105
-
106
- should "compile a param tag-call with a body" do
107
- assert_compiles_to "<% _output(call_tag_parameter(:foo, {}, { :default => proc { |_foo__default_content| new_context { %>abc<% } }, }, all_parameters, :foo)) %>",
108
- "<foo param>abc</foo>",
109
- :in_def
110
- end
111
-
112
- should "compile a param tag-call with a body and a call to <param_content/>" do
113
- assert_compiles_to "<% _output(call_tag_parameter(:foo, {}, { :default => proc { |_foo__default_content| new_context { %>!!<%= _foo__default_content && _foo__default_content.call %>!!<% } }, }, all_parameters, :foo)) %>",
114
- "<foo param>!!<param-content/>!!</foo>",
115
- :in_def
116
-
117
- end
118
-
119
- should "compile param template-calls as calls to `call_tag_parameter`" do
120
- assert_compiles_to "<% _output(call_tag_parameter(:foo, {}, {}, all_parameters, :foo)) %>",
121
- "<foo param/>",
122
- :in_def
123
- end
124
-
125
- should "compile param tag calls with parameters as calls to `call_tag_parameter`" do
126
- assert_compiles_to '<% _output(call_tag_parameter(:foo, {}, {:a => proc { [{:x => "1"}, {}] }, }, all_parameters, :foo)) %>',
127
- "<foo param><a: x='1'/></foo>",
128
- :in_def
129
- end
130
-
131
- should "compile parameters with param" do
132
- assert_compiles_to '<% _output(foo({}, {:abc => merge_tag_parameter(proc { [{}, {}] }, all_parameters[:abc]), })) %>',
133
- "<foo><abc: param/></foo>",
134
- :in_def
135
- end
136
-
137
- should "compile tag parameters with named params" do
138
- assert_compiles_to '<% _output(foo({}, {:abc => merge_tag_parameter(proc { [{}, {}] }, all_parameters[:x]), })) %>',
139
- "<foo><abc: param='x'/></foo>",
140
- :in_def
141
- end
142
-
143
- should "compile tag parameters with param and attributes" do
144
- assert_compiles_to '<% _output(foo({}, {:abc => merge_tag_parameter(proc { [{:a => "b"}, {}] }, all_parameters[:x]), })) %>',
145
- "<foo><abc: param='x' a='b'/></foo>",
146
- :in_def
147
- end
148
-
149
- should "compile tag parameters with param and a tag body" do
150
- assert_compiles_to(
151
- '<% _output(foo({}, {:abc => merge_tag_parameter(' +
152
- 'proc { [{}, { :default => proc { |_abc__default_content| new_context { %>ha!<% } }, }] }, all_parameters[:abc]), })) %>',
153
- "<foo><abc: param>ha!</abc></foo>",
154
- :in_def)
155
-
156
- end
157
-
158
- should "compile tag parameters with param and nested parameters" do
159
- assert_compiles_to(
160
- '<% _output(foo({}, {:baa => merge_tag_parameter(' +
161
- 'proc { [{}, {:x => proc { [{}, { :default => proc { |_x__default_content| new_context { %>hello<% } }, }] }, }] }, all_parameters[:baa]), })) %>',
162
- "<foo><baa: param><x:>hello</x:></baa:></foo>",
163
- :in_def)
164
- end
165
-
166
- # --- Compilation: Calling tags with parameters --- #
167
-
168
- should "compile tag parameters as procs" do
169
- assert_compiles_to(
170
- '<% _output(foo({}, {' +
171
- ':x => proc { [{}, { :default => proc { |_x__default_content| new_context { %>hello<% } }, }] }, ' +
172
- ':y => proc { [{}, { :default => proc { |_y__default_content| new_context { %>world<% } }, }] }, })) %>',
173
- "<foo><x:>hello</x><y:>world</y:></foo>"
174
- )
175
- end
176
-
177
- should "compile tag parameters with attributes" do
178
- assert_compiles_to(
179
- '<% _output(foo({}, {:abc => proc { [{:x => "1"}, { :default => proc { |_abc__default_content| new_context { %>hello<% } }, }] }, })) %>',
180
- "<foo><abc: x='1'>hello</abc></foo>"
181
- )
182
- end
183
-
184
- should "allow :foo as a shorthand for field='foo' on template tags" do
185
- assert_compiles_to '<% _output(foo({:field => "name"}, {})) %>', "<foo:name/>"
186
- end
187
-
188
- should "compile template parameters which are themselves templates" do
189
- # Tag parameters with nested tag parameters are procs that return
190
- # a pair of hashes, the first is the attributes, the second is the
191
- # sub-template procs
192
- assert_compiles_to(
193
- '<% _output(foo({}, ' +
194
- '{:baa => proc { [{:x => "1"}, {:a => proc { [{}, { :default => proc { |_a__default_content| new_context { %>hello<% } }, }] }, }] }, })) %>',
195
- "<foo><baa: x='1'><a:>hello</a></baa></foo>")
196
- end
197
-
198
- should "compile 'replace' parameters" do
199
- # A replace parameter is detected at runtime by the arity of the
200
- # block == 1 (for a normal parameter it would be 0). See
201
- # TemplateEnvironment#call_tag_parameter
202
- assert_compiles_to(
203
- '<% _output(page({}, {:head_replacement => proc { |_head_restore| new_context { %>abc<% } }, })) %>',
204
- "<page><head: replace>abc</head></page>"
205
- )
206
- end
207
-
208
- should "compile 'replace' parameters where the restore contains a default parameter call" do
209
- assert_compiles_to(
210
- '<% _output(page({}, {:head_replacement => proc { |_head_restore| new_context { %>abc ' +
211
- '<% _output(_head_restore.call({}, { :default => proc { |_head__default_content| new_context { %>blah<% } }, })) %>' +
212
- '<% } }, })) %>',
213
-
214
- "<page><head: replace>abc <head restore>blah</head></head></page>"
215
- )
216
- end
217
-
218
- should "compile 'replace' tag parameters with a default parameter call" do
219
- assert_compiles_to(
220
- '<% _output(page({}, {:head_replacement => proc { |_head_restore| new_context { %>abc ' +
221
- '<% _output(_head_restore.call({}, {})) %>' +
222
- '<% } }, })) %>',
223
- "<page><head: replace>abc <head restore/></head></page>")
224
- end
225
-
226
-
227
- # --- Compilation: Syntax sugar for before, after, append, prepend --- #
228
-
229
- should "compile 'before' parameters" do
230
- assert_compiles_to(
231
- '<% _output(page({}, {:head_replacement => proc { |_head_restore| new_context { %>abc' +
232
- '<% _output(_head_restore.call({}, {})) %>' +
233
- '<% } }, })) %>',
234
- "<page><before-head:>abc</before-head></page>")
235
- end
236
-
237
- should "compile 'after' parameters" do
238
- assert_compiles_to(
239
- '<% _output(page({}, {:head_replacement => proc { |_head_restore| new_context { %>' +
240
- '<% _output(_head_restore.call({}, {})) %>' +
241
- 'abc<% } }, })) %>',
242
- "<page><after-head:>abc</after-head></page>")
243
- end
244
-
245
- should "compile 'apppend' parameters" do
246
- assert_compiles_to(
247
- '<% _output(page({}, {:head => proc { [{}, { :default => proc { |_head__default_content| new_context { %>' +
248
- '<%= _head__default_content && _head__default_content.call %>:o)' +
249
- '<% } } } ] }, })) %>',
250
- "<page><append-head:>:o)</append-head></page>")
251
- end
252
-
253
- should "compile 'prepend' parameters" do
254
- assert_compiles_to(
255
- '<% _output(page({}, {:head => proc { [{}, { :default => proc { |_head__default_content| new_context { %>' +
256
- ':o)<%= _head__default_content && _head__default_content.call %>' +
257
- '<% } } } ] }, })) %>',
258
- "<page><prepend-head:>:o)</prepend-head></page>")
259
- end
260
-
261
- end