drnic-liquid 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. data/CHANGELOG +44 -0
  2. data/History.txt +44 -0
  3. data/MIT-LICENSE +20 -0
  4. data/Manifest.txt +34 -0
  5. data/README.rdoc +44 -0
  6. data/Rakefile +30 -0
  7. data/example/server/example_servlet.rb +37 -0
  8. data/example/server/liquid_servlet.rb +28 -0
  9. data/example/server/server.rb +12 -0
  10. data/example/server/templates/index.liquid +6 -0
  11. data/example/server/templates/products.liquid +45 -0
  12. data/init.rb +8 -0
  13. data/lib/extras/liquid_view.rb +51 -0
  14. data/lib/liquid.rb +70 -0
  15. data/lib/liquid/block.rb +102 -0
  16. data/lib/liquid/condition.rb +120 -0
  17. data/lib/liquid/context.rb +221 -0
  18. data/lib/liquid/document.rb +17 -0
  19. data/lib/liquid/drop.rb +51 -0
  20. data/lib/liquid/errors.rb +11 -0
  21. data/lib/liquid/extensions.rb +56 -0
  22. data/lib/liquid/file_system.rb +62 -0
  23. data/lib/liquid/htmltags.rb +74 -0
  24. data/lib/liquid/module_ex.rb +62 -0
  25. data/lib/liquid/standardfilters.rb +209 -0
  26. data/lib/liquid/strainer.rb +51 -0
  27. data/lib/liquid/tag.rb +26 -0
  28. data/lib/liquid/tags/assign.rb +33 -0
  29. data/lib/liquid/tags/capture.rb +35 -0
  30. data/lib/liquid/tags/case.rb +83 -0
  31. data/lib/liquid/tags/comment.rb +9 -0
  32. data/lib/liquid/tags/cycle.rb +59 -0
  33. data/lib/liquid/tags/for.rb +136 -0
  34. data/lib/liquid/tags/if.rb +79 -0
  35. data/lib/liquid/tags/ifchanged.rb +20 -0
  36. data/lib/liquid/tags/include.rb +55 -0
  37. data/lib/liquid/tags/unless.rb +33 -0
  38. data/lib/liquid/template.rb +147 -0
  39. data/lib/liquid/variable.rb +49 -0
  40. data/liquid.gemspec +40 -0
  41. data/performance/shopify.rb +92 -0
  42. data/performance/shopify/comment_form.rb +33 -0
  43. data/performance/shopify/database.rb +45 -0
  44. data/performance/shopify/json_filter.rb +7 -0
  45. data/performance/shopify/liquid.rb +18 -0
  46. data/performance/shopify/money_filter.rb +18 -0
  47. data/performance/shopify/paginate.rb +93 -0
  48. data/performance/shopify/shop_filter.rb +98 -0
  49. data/performance/shopify/tag_filter.rb +25 -0
  50. data/performance/shopify/vision.database.yml +945 -0
  51. data/performance/shopify/weight_filter.rb +11 -0
  52. data/performance/tests/dropify/article.liquid +74 -0
  53. data/performance/tests/dropify/blog.liquid +33 -0
  54. data/performance/tests/dropify/cart.liquid +66 -0
  55. data/performance/tests/dropify/collection.liquid +22 -0
  56. data/performance/tests/dropify/index.liquid +47 -0
  57. data/performance/tests/dropify/page.liquid +8 -0
  58. data/performance/tests/dropify/product.liquid +68 -0
  59. data/performance/tests/dropify/theme.liquid +105 -0
  60. data/performance/tests/ripen/article.liquid +74 -0
  61. data/performance/tests/ripen/blog.liquid +13 -0
  62. data/performance/tests/ripen/cart.liquid +54 -0
  63. data/performance/tests/ripen/collection.liquid +29 -0
  64. data/performance/tests/ripen/index.liquid +32 -0
  65. data/performance/tests/ripen/page.liquid +4 -0
  66. data/performance/tests/ripen/product.liquid +75 -0
  67. data/performance/tests/ripen/theme.liquid +85 -0
  68. data/performance/tests/tribble/404.liquid +56 -0
  69. data/performance/tests/tribble/article.liquid +98 -0
  70. data/performance/tests/tribble/blog.liquid +41 -0
  71. data/performance/tests/tribble/cart.liquid +134 -0
  72. data/performance/tests/tribble/collection.liquid +70 -0
  73. data/performance/tests/tribble/index.liquid +94 -0
  74. data/performance/tests/tribble/page.liquid +56 -0
  75. data/performance/tests/tribble/product.liquid +116 -0
  76. data/performance/tests/tribble/search.liquid +51 -0
  77. data/performance/tests/tribble/theme.liquid +90 -0
  78. data/performance/tests/vogue/article.liquid +66 -0
  79. data/performance/tests/vogue/blog.liquid +32 -0
  80. data/performance/tests/vogue/cart.liquid +58 -0
  81. data/performance/tests/vogue/collection.liquid +19 -0
  82. data/performance/tests/vogue/index.liquid +22 -0
  83. data/performance/tests/vogue/page.liquid +3 -0
  84. data/performance/tests/vogue/product.liquid +62 -0
  85. data/performance/tests/vogue/theme.liquid +122 -0
  86. data/test/assign_test.rb +11 -0
  87. data/test/block_test.rb +58 -0
  88. data/test/condition_test.rb +109 -0
  89. data/test/context_test.rb +482 -0
  90. data/test/drop_test.rb +162 -0
  91. data/test/error_handling_test.rb +89 -0
  92. data/test/extra/breakpoint.rb +547 -0
  93. data/test/extra/caller.rb +80 -0
  94. data/test/file_system_test.rb +30 -0
  95. data/test/filter_test.rb +95 -0
  96. data/test/helper.rb +20 -0
  97. data/test/html_tag_test.rb +31 -0
  98. data/test/if_else_test.rb +131 -0
  99. data/test/include_tag_test.rb +115 -0
  100. data/test/module_ex_test.rb +89 -0
  101. data/test/output_test.rb +121 -0
  102. data/test/parsing_quirks_test.rb +41 -0
  103. data/test/regexp_test.rb +45 -0
  104. data/test/security_test.rb +41 -0
  105. data/test/standard_filter_test.rb +161 -0
  106. data/test/standard_tag_test.rb +400 -0
  107. data/test/statements_test.rb +137 -0
  108. data/test/strainer_test.rb +21 -0
  109. data/test/template_test.rb +26 -0
  110. data/test/test_helper.rb +20 -0
  111. data/test/unless_else_test.rb +27 -0
  112. data/test/variable_test.rb +172 -0
  113. metadata +187 -0
@@ -0,0 +1,20 @@
1
+ module Liquid
2
+ class Ifchanged < Block
3
+
4
+ def render(context)
5
+ context.stack do
6
+
7
+ output = render_all(@nodelist, context)
8
+
9
+ if output != context.registers[:ifchanged]
10
+ context.registers[:ifchanged] = output
11
+ output
12
+ else
13
+ ''
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ Template.register_tag('ifchanged', Ifchanged)
20
+ end
@@ -0,0 +1,55 @@
1
+ module Liquid
2
+ class Include < Tag
3
+ Syntax = /(#{QuotedFragment}+)(\s+(?:with|for)\s+(#{QuotedFragment}+))?/
4
+
5
+ def initialize(tag_name, markup, tokens)
6
+ if markup =~ Syntax
7
+
8
+ @template_name = $1
9
+ @variable_name = $3
10
+ @attributes = {}
11
+
12
+ markup.scan(TagAttributes) do |key, value|
13
+ @attributes[key] = value
14
+ end
15
+
16
+ else
17
+ raise SyntaxError.new("Error in tag 'include' - Valid syntax: include '[template]' (with|for) [object|collection]")
18
+ end
19
+
20
+ super
21
+ end
22
+
23
+ def parse(tokens)
24
+ end
25
+
26
+ def render(context)
27
+ source = Liquid::Template.file_system.read_template_file(context[@template_name])
28
+ partial = Liquid::Template.parse(source)
29
+
30
+ variable = context[@variable_name || @template_name[1..-2]]
31
+
32
+ context.stack do
33
+ @attributes.each do |key, value|
34
+ context[key] = context[value]
35
+ end
36
+
37
+ if variable.is_a?(Array)
38
+
39
+ variable.collect do |variable|
40
+ context[@template_name[1..-2]] = variable
41
+ partial.render(context)
42
+ end
43
+
44
+ else
45
+
46
+ context[@template_name[1..-2]] = variable
47
+ partial.render(context)
48
+
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ Template.register_tag('include', Include)
55
+ end
@@ -0,0 +1,33 @@
1
+ require File.dirname(__FILE__) + '/if'
2
+
3
+ module Liquid
4
+
5
+ # Unless is a conditional just like 'if' but works on the inverse logic.
6
+ #
7
+ # {% unless x < 0 %} x is greater than zero {% end %}
8
+ #
9
+ class Unless < If
10
+ def render(context)
11
+ context.stack do
12
+
13
+ # First condition is interpreted backwards ( if not )
14
+ block = @blocks.first
15
+ unless block.evaluate(context)
16
+ return render_all(block.attachment, context)
17
+ end
18
+
19
+ # After the first condition unless works just like if
20
+ @blocks[1..-1].each do |block|
21
+ if block.evaluate(context)
22
+ return render_all(block.attachment, context)
23
+ end
24
+ end
25
+
26
+ ''
27
+ end
28
+ end
29
+ end
30
+
31
+
32
+ Template.register_tag('unless', Unless)
33
+ end
@@ -0,0 +1,147 @@
1
+ module Liquid
2
+
3
+ # Templates are central to liquid.
4
+ # Interpretating templates is a two step process. First you compile the
5
+ # source code you got. During compile time some extensive error checking is performed.
6
+ # your code should expect to get some SyntaxErrors.
7
+ #
8
+ # After you have a compiled template you can then <tt>render</tt> it.
9
+ # You can use a compiled template over and over again and keep it cached.
10
+ #
11
+ # Example:
12
+ #
13
+ # template = Liquid::Template.parse(source)
14
+ # template.render('user_name' => 'bob')
15
+ #
16
+ class Template
17
+ attr_accessor :root
18
+ @@file_system = BlankFileSystem.new
19
+
20
+ class << self
21
+ def file_system
22
+ @@file_system
23
+ end
24
+
25
+ def file_system=(obj)
26
+ @@file_system = obj
27
+ end
28
+
29
+ def register_tag(name, klass)
30
+ tags[name.to_s] = klass
31
+ end
32
+
33
+ def tags
34
+ @tags ||= {}
35
+ end
36
+
37
+ # Pass a module with filter methods which should be available
38
+ # to all liquid views. Good for registering the standard library
39
+ def register_filter(mod)
40
+ Strainer.global_filter(mod)
41
+ end
42
+
43
+ # creates a new <tt>Template</tt> object from liquid source code
44
+ def parse(source)
45
+ template = Template.new
46
+ template.parse(source)
47
+ template
48
+ end
49
+ end
50
+
51
+ # creates a new <tt>Template</tt> from an array of tokens. Use <tt>Template.parse</tt> instead
52
+ def initialize
53
+ end
54
+
55
+ # Parse source code.
56
+ # Returns self for easy chaining
57
+ def parse(source)
58
+ @root = Document.new(tokenize(source))
59
+ self
60
+ end
61
+
62
+ def registers
63
+ @registers ||= {}
64
+ end
65
+
66
+ def assigns
67
+ @assigns ||= {}
68
+ end
69
+
70
+ def errors
71
+ @errors ||= []
72
+ end
73
+
74
+ # Render takes a hash with local variables.
75
+ #
76
+ # if you use the same filters over and over again consider registering them globally
77
+ # with <tt>Template.register_filter</tt>
78
+ #
79
+ # Following options can be passed:
80
+ #
81
+ # * <tt>filters</tt> : array with local filters
82
+ # * <tt>registers</tt> : hash with register variables. Those can be accessed from
83
+ # filters and tags and might be useful to integrate liquid more with its host application
84
+ #
85
+ def render(*args)
86
+ return '' if @root.nil?
87
+
88
+ context = case args.first
89
+ when Liquid::Context
90
+ args.shift
91
+ when Hash
92
+ a = args.shift
93
+ assigns.each { |k,v| a[k] = v unless a.has_key?(k) }
94
+ Context.new(a, registers, @rethrow_errors)
95
+ when nil
96
+ Context.new(assigns.dup, registers, @rethrow_errors)
97
+ else
98
+ raise ArgumentError, "Expect Hash or Liquid::Context as parameter"
99
+ end
100
+
101
+ case args.last
102
+ when Hash
103
+ options = args.pop
104
+
105
+ if options[:registers].is_a?(Hash)
106
+ self.registers.merge!(options[:registers])
107
+ end
108
+
109
+ if options[:filters]
110
+ context.add_filters(options[:filters])
111
+ end
112
+
113
+ when Module
114
+ context.add_filters(args.pop)
115
+ when Array
116
+ context.add_filters(args.pop)
117
+ end
118
+
119
+ begin
120
+ # render the nodelist.
121
+ # for performance reasons we get a array back here. join will make a string out of it
122
+ @root.render(context).join
123
+ ensure
124
+ @errors = context.errors
125
+ end
126
+ end
127
+
128
+ def render!(*args)
129
+ @rethrow_errors = true; render(*args)
130
+ end
131
+
132
+ private
133
+
134
+ # Uses the <tt>Liquid::TemplateParser</tt> regexp to tokenize the passed source
135
+ def tokenize(source)
136
+ source = source.source if source.respond_to?(:source)
137
+ return [] if source.to_s.empty?
138
+ tokens = source.split(TemplateParser)
139
+
140
+ # removes the rogue empty element at the beginning of the array
141
+ tokens.shift if tokens[0] and tokens[0].empty?
142
+
143
+ tokens
144
+ end
145
+
146
+ end
147
+ end
@@ -0,0 +1,49 @@
1
+ module Liquid
2
+
3
+ # Holds variables. Variables are only loaded "just in time"
4
+ # and are not evaluated as part of the render stage
5
+ #
6
+ # {{ monkey }}
7
+ # {{ user.name }}
8
+ #
9
+ # Variables can be combined with filters:
10
+ #
11
+ # {{ user | link }}
12
+ #
13
+ class Variable
14
+ attr_accessor :filters, :name
15
+
16
+ def initialize(markup)
17
+ @markup = markup
18
+ @name = nil
19
+ @filters = []
20
+ if match = markup.match(/\s*(#{QuotedFragment})/)
21
+ @name = match[1]
22
+ if markup.match(/#{FilterSeparator}\s*(.*)/)
23
+ filters = Regexp.last_match(1).split(/#{FilterSeparator}/)
24
+ filters.each do |f|
25
+ if matches = f.match(/\s*(\w+)/)
26
+ filtername = matches[1]
27
+ filterargs = f.scan(/(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*(#{QuotedFragment})/).flatten
28
+ @filters << [filtername.to_sym, filterargs]
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ def render(context)
36
+ return '' if @name.nil?
37
+ @filters.inject(context[@name]) do |output, filter|
38
+ filterargs = filter[1].to_a.collect do |a|
39
+ context[a]
40
+ end
41
+ begin
42
+ output = context.invoke(filter[0], output, *filterargs)
43
+ rescue FilterNotFound
44
+ raise FilterNotFound, "Error - filter '#{filter[0]}' in '#{@markup.strip}' could not be found."
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,40 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{drnic-liquid}
3
+ s.version = "2.1.0"
4
+
5
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6
+ s.authors = ["Tobias Luetke"]
7
+ s.date = %q{2009-08-31}
8
+ s.description = %q{A secure non evaling end user template engine with aesthetic markup.
9
+
10
+ Liquid is a template engine which I wrote for very specific requirements.
11
+
12
+ * It has to have beautiful and simple markup.
13
+ Template engines which don't produce good looking markup are no fun to use.
14
+ * It needs to be non evaling and secure. Liquid templates are made so that users can edit them. You don't want to run code on your server which your users wrote.
15
+ * It has to be stateless. Compile and render steps have to be seperate so that the expensive parsing and compiling can be done once and later on you can
16
+ just render it passing in a hash with local variables and objects.}
17
+ s.email = ["tobi@leetsoft.com"]
18
+ s.extra_rdoc_files = ["History.txt", "Manifest.txt"]
19
+ s.files = ["CHANGELOG", "History.txt", "MIT-LICENSE", "Manifest.txt", "README.rdoc", "Rakefile", "example/server/example_servlet.rb", "example/server/liquid_servlet.rb", "example/server/server.rb", "example/server/templates/index.liquid", "example/server/templates/products.liquid", "init.rb", "lib/extras/liquid_view.rb", "lib/liquid.rb", "lib/liquid/block.rb", "lib/liquid/condition.rb", "lib/liquid/context.rb", "lib/liquid/document.rb", "lib/liquid/drop.rb", "lib/liquid/errors.rb", "lib/liquid/extensions.rb", "lib/liquid/file_system.rb", "lib/liquid/htmltags.rb", "lib/liquid/module_ex.rb", "lib/liquid/standardfilters.rb", "lib/liquid/strainer.rb", "lib/liquid/tag.rb", "lib/liquid/tags/assign.rb", "lib/liquid/tags/capture.rb", "lib/liquid/tags/case.rb", "lib/liquid/tags/comment.rb", "lib/liquid/tags/cycle.rb", "lib/liquid/tags/for.rb", "lib/liquid/tags/if.rb", "lib/liquid/tags/ifchanged.rb", "lib/liquid/tags/include.rb", "lib/liquid/tags/unless.rb", "lib/liquid/template.rb", "lib/liquid/variable.rb", "liquid.gemspec", "performance/shopify.rb", "performance/shopify/comment_form.rb", "performance/shopify/database.rb", "performance/shopify/json_filter.rb", "performance/shopify/liquid.rb", "performance/shopify/money_filter.rb", "performance/shopify/paginate.rb", "performance/shopify/shop_filter.rb", "performance/shopify/tag_filter.rb", "performance/shopify/vision.database.yml", "performance/shopify/weight_filter.rb", "performance/tests/dropify/article.liquid", "performance/tests/dropify/blog.liquid", "performance/tests/dropify/cart.liquid", "performance/tests/dropify/collection.liquid", "performance/tests/dropify/index.liquid", "performance/tests/dropify/page.liquid", "performance/tests/dropify/product.liquid", "performance/tests/dropify/theme.liquid", "performance/tests/ripen/article.liquid", "performance/tests/ripen/blog.liquid", "performance/tests/ripen/cart.liquid", "performance/tests/ripen/collection.liquid", "performance/tests/ripen/index.liquid", "performance/tests/ripen/page.liquid", "performance/tests/ripen/product.liquid", "performance/tests/ripen/theme.liquid", "performance/tests/tribble/404.liquid", "performance/tests/tribble/article.liquid", "performance/tests/tribble/blog.liquid", "performance/tests/tribble/cart.liquid", "performance/tests/tribble/collection.liquid", "performance/tests/tribble/index.liquid", "performance/tests/tribble/page.liquid", "performance/tests/tribble/product.liquid", "performance/tests/tribble/search.liquid", "performance/tests/tribble/theme.liquid", "performance/tests/vogue/article.liquid", "performance/tests/vogue/blog.liquid", "performance/tests/vogue/cart.liquid", "performance/tests/vogue/collection.liquid", "performance/tests/vogue/index.liquid", "performance/tests/vogue/page.liquid", "performance/tests/vogue/product.liquid", "performance/tests/vogue/theme.liquid", "test/assign_test.rb", "test/block_test.rb", "test/condition_test.rb", "test/context_test.rb", "test/drop_test.rb", "test/error_handling_test.rb", "test/extra/breakpoint.rb", "test/extra/caller.rb", "test/file_system_test.rb", "test/filter_test.rb", "test/helper.rb", "test/html_tag_test.rb", "test/if_else_test.rb", "test/include_tag_test.rb", "test/module_ex_test.rb", "test/output_test.rb", "test/parsing_quirks_test.rb", "test/regexp_test.rb", "test/security_test.rb", "test/standard_filter_test.rb", "test/standard_tag_test.rb", "test/statements_test.rb", "test/strainer_test.rb", "test/template_test.rb", "test/test_helper.rb", "test/unless_else_test.rb", "test/variable_test.rb"]
20
+ s.homepage = %q{http://www.liquidmarkup.org}
21
+ s.rdoc_options = ["--main", "README.rdoc"]
22
+ s.require_paths = ["lib"]
23
+ s.rubyforge_project = %q{liquid}
24
+ s.rubygems_version = %q{1.3.4}
25
+ s.summary = %q{A secure non evaling end user template engine with aesthetic markup}
26
+ s.test_files = ["test/test_helper.rb"]
27
+
28
+ if s.respond_to? :specification_version then
29
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
30
+ s.specification_version = 3
31
+
32
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
33
+ s.add_development_dependency(%q<hoe>, [">= 2.3.3"])
34
+ else
35
+ s.add_dependency(%q<hoe>, [">= 2.3.3"])
36
+ end
37
+ else
38
+ s.add_dependency(%q<hoe>, [">= 2.3.3"])
39
+ end
40
+ end
@@ -0,0 +1,92 @@
1
+ # This profiler run simulates Shopify.
2
+ # We are looking in the tests directory for liquid files and render them within the designated layout file.
3
+ # We will also export a substantial database to liquid which the templates can render values of.
4
+ # All this is to make the benchmark as non syntetic as possible. All templates and tests are lifted from
5
+ # direct real-world usage and the profiler measures code that looks very similar to the way it looks in
6
+ # Shopify which is likely the biggest user of liquid in the world which something to the tune of several
7
+ # million Template#render calls a day.
8
+
9
+ require 'rubygems'
10
+ require 'active_support'
11
+ require 'yaml'
12
+ require 'digest/md5'
13
+ require File.dirname(__FILE__) + '/shopify/liquid'
14
+ require File.dirname(__FILE__) + '/shopify/database.rb'
15
+
16
+ require "ruby-prof" rescue fail("install ruby-prof extension/gem")
17
+
18
+ class ThemeProfiler
19
+
20
+ # Load all templates into memory, do this now so that
21
+ # we don't profile IO.
22
+ def initialize
23
+ @tests = Dir[File.dirname(__FILE__) + '/tests/**/*.liquid'].collect do |test|
24
+ next if File.basename(test) == 'theme.liquid'
25
+
26
+ theme_path = File.dirname(test) + '/theme.liquid'
27
+
28
+ [File.read(test), (File.file?(theme_path) ? File.read(theme_path) : nil), test]
29
+ end.compact
30
+ end
31
+
32
+
33
+ def profile
34
+ RubyProf.measure_mode = RubyProf::WALL_TIME
35
+
36
+ # Dup assigns because will make some changes to them
37
+ assigns = Database.tables.dup
38
+
39
+ @tests.each do |liquid, layout, template_name|
40
+
41
+ # Compute page_tempalte outside of profiler run, uninteresting to profiler
42
+ html = nil
43
+ page_template = File.basename(template_name, File.extname(template_name))
44
+
45
+ # Profile compiling and rendering both
46
+ RubyProf.resume { html = compile_and_render(liquid, layout, assigns, page_template) }
47
+
48
+ # return the result and the MD5 of the content, this can be used to detect regressions between liquid version
49
+ $stdout.puts "* rendered template %s, content: %s" % [template_name, Digest::MD5.hexdigest(html)]
50
+
51
+ # Uncomment to dump html files to /tmp so that you can inspect for errors
52
+ # File.open("/tmp/#{File.basename(template_name)}.html", "w+") { |fp| fp <<html}
53
+ end
54
+
55
+ RubyProf.stop
56
+ end
57
+
58
+ def compile_and_render(template, layout, assigns, page_template)
59
+ tmpl = Liquid::Template.new
60
+ tmpl.assigns['page_title'] = 'Page title'
61
+ tmpl.assigns['template'] = page_template
62
+
63
+ content_for_layout = tmpl.parse(template).render(assigns)
64
+
65
+ if layout
66
+ assigns['content_for_layout'] = content_for_layout
67
+ tmpl.parse(layout).render(assigns)
68
+ else
69
+ content_for_layout
70
+ end
71
+ end
72
+ end
73
+
74
+
75
+ profiler = ThemeProfiler.new
76
+
77
+ puts 'Running profiler...'
78
+
79
+ results = profiler.profile
80
+
81
+ puts 'Success'
82
+ puts
83
+
84
+ [RubyProf::FlatPrinter, RubyProf::GraphPrinter, RubyProf::GraphHtmlPrinter, RubyProf::CallTreePrinter].each do |klass|
85
+ filename = (ENV['TMP'] || '/tmp') + (klass.name.include?('Html') ? "/liquid.#{klass.name.downcase}.html" : "/liquid.#{klass.name.downcase}.txt")
86
+ filename.gsub!(/:+/, '_')
87
+ File.open(filename, "w+") { |fp| klass.new(results).print(fp) }
88
+ $stderr.puts "wrote #{klass.name} output to #{filename}"
89
+ end
90
+
91
+
92
+
@@ -0,0 +1,33 @@
1
+ class CommentForm < Liquid::Block
2
+ Syntax = /(#{Liquid::VariableSignature}+)/
3
+
4
+ def initialize(tag_name, markup, tokens)
5
+ if markup =~ Syntax
6
+ @variable_name = $1
7
+ @attributes = {}
8
+ else
9
+ raise SyntaxError.new("Syntax Error in 'comment_form' - Valid syntax: comment_form [article]")
10
+ end
11
+
12
+ super
13
+ end
14
+
15
+ def render(context)
16
+ article = context[@variable_name]
17
+
18
+ context.stack do
19
+ context['form'] = {
20
+ 'posted_successfully?' => context.registers[:posted_successfully],
21
+ 'errors' => context['comment.errors'],
22
+ 'author' => context['comment.author'],
23
+ 'email' => context['comment.email'],
24
+ 'body' => context['comment.body']
25
+ }
26
+ wrap_in_form(article, render_all(@nodelist, context))
27
+ end
28
+ end
29
+
30
+ def wrap_in_form(article, input)
31
+ %Q{<form id="article-#{article.id}-comment-form" class="comment-form" method="post" action="">\n#{input}\n</form>}
32
+ end
33
+ end