aslakjo-aslakjo-comatose 2.0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +195 -0
- data/INSTALL +20 -0
- data/LICENSE +20 -0
- data/MANIFEST +91 -0
- data/README.markdown +159 -0
- data/Rakefile +176 -0
- data/SPECS +61 -0
- data/about.yml +7 -0
- data/bin/comatose +112 -0
- data/comatose.gemspec +113 -0
- data/generators/comatose_migration/USAGE +15 -0
- data/generators/comatose_migration/comatose_migration_generator.rb +74 -0
- data/generators/comatose_migration/templates/migration.rb +35 -0
- data/generators/comatose_migration/templates/v4_upgrade.rb +15 -0
- data/generators/comatose_migration/templates/v6_upgrade.rb +23 -0
- data/generators/comatose_migration/templates/v7_upgrade.rb +22 -0
- data/init.rb +2 -0
- data/install.rb +18 -0
- data/lib/acts_as_versioned.rb +543 -0
- data/lib/comatose.rb +33 -0
- data/lib/comatose/comatose_drop.rb +79 -0
- data/lib/comatose/configuration.rb +69 -0
- data/lib/comatose/page_wrapper.rb +119 -0
- data/lib/comatose/processing_context.rb +69 -0
- data/lib/comatose/tasks/admin.rb +60 -0
- data/lib/comatose/tasks/data.rb +82 -0
- data/lib/comatose/tasks/setup.rb +52 -0
- data/lib/comatose/version.rb +4 -0
- data/lib/comatose_admin_controller.rb +395 -0
- data/lib/comatose_admin_helper.rb +37 -0
- data/lib/comatose_controller.rb +138 -0
- data/lib/comatose_helper.rb +3 -0
- data/lib/comatose_page.rb +141 -0
- data/lib/liquid.rb +52 -0
- data/lib/liquid/block.rb +96 -0
- data/lib/liquid/context.rb +190 -0
- data/lib/liquid/document.rb +17 -0
- data/lib/liquid/drop.rb +48 -0
- data/lib/liquid/errors.rb +7 -0
- data/lib/liquid/extensions.rb +53 -0
- data/lib/liquid/file_system.rb +62 -0
- data/lib/liquid/htmltags.rb +64 -0
- data/lib/liquid/standardfilters.rb +111 -0
- data/lib/liquid/standardtags.rb +399 -0
- data/lib/liquid/strainer.rb +42 -0
- data/lib/liquid/tag.rb +25 -0
- data/lib/liquid/template.rb +88 -0
- data/lib/liquid/variable.rb +39 -0
- data/lib/redcloth.rb +1129 -0
- data/lib/support/class_options.rb +36 -0
- data/lib/support/inline_rendering.rb +48 -0
- data/lib/support/route_mapper.rb +50 -0
- data/lib/text_filters.rb +140 -0
- data/lib/text_filters/markdown.rb +14 -0
- data/lib/text_filters/markdown_smartypants.rb +15 -0
- data/lib/text_filters/none.rb +8 -0
- data/lib/text_filters/rdoc.rb +13 -0
- data/lib/text_filters/simple.rb +8 -0
- data/lib/text_filters/textile.rb +15 -0
- data/rails/init.rb +3 -0
- data/resources/layouts/comatose_admin_template.html.erb +28 -0
- data/resources/public/images/collapsed.gif +0 -0
- data/resources/public/images/expanded.gif +0 -0
- data/resources/public/images/no-children.gif +0 -0
- data/resources/public/images/page.gif +0 -0
- data/resources/public/images/spinner.gif +0 -0
- data/resources/public/images/title-hover-bg.gif +0 -0
- data/resources/public/javascripts/comatose_admin.js +401 -0
- data/resources/public/stylesheets/comatose_admin.css +404 -0
- data/tasks/comatose.rake +9 -0
- data/test/behaviors.rb +106 -0
- data/test/fixtures/comatose_pages.yml +96 -0
- data/test/functional/comatose_admin_controller_test.rb +114 -0
- data/test/functional/comatose_controller_test.rb +44 -0
- data/test/javascripts/test.html +26 -0
- data/test/javascripts/test_runner.js +307 -0
- data/test/test_helper.rb +55 -0
- data/test/unit/class_options_test.rb +52 -0
- data/test/unit/comatose_page_test.rb +136 -0
- data/test/unit/processing_context_test.rb +108 -0
- data/test/unit/text_filters_test.rb +52 -0
- data/views/comatose_admin/_form.html.erb +96 -0
- data/views/comatose_admin/_page_list_item.html.erb +60 -0
- data/views/comatose_admin/delete.html.erb +18 -0
- data/views/comatose_admin/edit.html.erb +5 -0
- data/views/comatose_admin/index.html.erb +29 -0
- data/views/comatose_admin/new.html.erb +5 -0
- data/views/comatose_admin/reorder.html.erb +30 -0
- data/views/comatose_admin/versions.html.erb +40 -0
- data/views/layouts/comatose_admin.html.erb +837 -0
- data/views/layouts/comatose_admin_customize.html.erb +28 -0
- data/views/layouts/comatose_content.html.erb +17 -0
- metadata +148 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
module ComatoseAdminHelper
|
2
|
+
|
3
|
+
# Checks the hidden_meta_fields class variable for a specified field name...
|
4
|
+
def show_field?(key)
|
5
|
+
!Comatose.config.hidden_meta_fields.include? key
|
6
|
+
end
|
7
|
+
|
8
|
+
# Used in the Page Form to build an indented drop-down list of pages
|
9
|
+
def tree_select_box(nodes, selected= nil, hide= nil, label="Parent", add_initial=false)
|
10
|
+
level = 0
|
11
|
+
select_box = add_initial ? "<option value=0>No #{label}</option>\n" : ""
|
12
|
+
selected = nodes[0].id if selected.nil? and not add_initial
|
13
|
+
nodes.each {|node| select_box += add_select_tree_node(node, selected, level, hide) }
|
14
|
+
select_box += ''
|
15
|
+
end
|
16
|
+
# Called by tree_select_box
|
17
|
+
def add_select_tree_node(node, selected, level, hide)
|
18
|
+
padding = " " * level * 4
|
19
|
+
padding += '» ' unless level==0
|
20
|
+
hide_values = Array.new
|
21
|
+
hide_values << hide if hide
|
22
|
+
if node.id == selected
|
23
|
+
select_box = %Q|<option value="#{node.id}" selected="true">#{padding}#{node.title}</option>\n|
|
24
|
+
else
|
25
|
+
if hide_values.include?(node.id)
|
26
|
+
select_box = ''
|
27
|
+
else
|
28
|
+
select_box = %Q|<option value="#{node.id}">#{padding}#{node.title}</option>\n|
|
29
|
+
end
|
30
|
+
end
|
31
|
+
node.children.each do |child|
|
32
|
+
select_box += add_select_tree_node(child, selected, level + 1, hide) unless hide_values.include?(node.id)
|
33
|
+
end
|
34
|
+
select_box
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
# The controller for serving cms content...
|
2
|
+
class ComatoseController < ActionController::Base
|
3
|
+
unloadable
|
4
|
+
|
5
|
+
before_filter :handle_authorization, :set_content_type
|
6
|
+
after_filter :cache_cms_page
|
7
|
+
|
8
|
+
# Render a specific page
|
9
|
+
def show
|
10
|
+
page_name, page_ext = get_page_path
|
11
|
+
page = ComatosePage.find_by_path( page_name )
|
12
|
+
status = nil
|
13
|
+
if page.nil?
|
14
|
+
page = ComatosePage.find_by_path( '404' )
|
15
|
+
status = 404
|
16
|
+
end
|
17
|
+
# if it's still nil, well, send a 404 status
|
18
|
+
if page.nil?
|
19
|
+
render :nothing=>true, :status=>status
|
20
|
+
#raise ActiveRecord::RecordNotFound.new("Comatose page not found ")
|
21
|
+
else
|
22
|
+
# Make the page access 'safe'
|
23
|
+
@page = Comatose::PageWrapper.new(page)
|
24
|
+
# For accurate uri creation, tell the page class which is the active mount point...
|
25
|
+
ComatosePage.active_mount_info = get_active_mount_point(params[:index])
|
26
|
+
render :text=>page.to_html({'params'=>params.stringify_keys}), :layout=>get_page_layout, :status=>status
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
|
32
|
+
def handle_authorization
|
33
|
+
if Comatose.config.authorization.is_a? Proc
|
34
|
+
instance_eval &Comatose.config.authorization
|
35
|
+
elsif Comatose.config.authorization.is_a? Symbol
|
36
|
+
send(Comatose.config.authorization)
|
37
|
+
elsif defined? authorize
|
38
|
+
authorize
|
39
|
+
else
|
40
|
+
true
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def allow_page_cache?
|
45
|
+
# You should have access to the @page being rendered
|
46
|
+
true
|
47
|
+
end
|
48
|
+
|
49
|
+
# For use in the #show method... determines the current mount point
|
50
|
+
def get_active_mount_point( index )
|
51
|
+
Comatose.mount_points.each do |path_info|
|
52
|
+
if path_info[:index] == index
|
53
|
+
return path_info
|
54
|
+
end
|
55
|
+
end
|
56
|
+
{:root=>"", :index=>index}
|
57
|
+
end
|
58
|
+
|
59
|
+
# For use in the #show method... determines the current page path
|
60
|
+
def get_page_path
|
61
|
+
|
62
|
+
#in rails 2.0, params[:page] comes back as just an Array, so to_s doesn't do join('/')
|
63
|
+
if params[:page].is_a? Array
|
64
|
+
page_name = params[:page].join("/")
|
65
|
+
#in rails 1.x, params[:page] comes back as ActionController::Routing::PathSegment::Result
|
66
|
+
elsif params[:page].is_a? ActionController::Routing::PathSegment::Result
|
67
|
+
page_name = params[:page].to_s
|
68
|
+
else
|
69
|
+
logger.debug "get_page_path - params[:page] is an unrecognized type, may cause problems: #{params[:page].class}"
|
70
|
+
page_name = params[:page].to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
page_ext = page_name.split('.')[1] unless page_name.empty?
|
74
|
+
# TODO: Automatic support for page RSS feeds... ????
|
75
|
+
if page_name.nil? or page_name.empty?
|
76
|
+
page_name = params[:index]
|
77
|
+
params[:cache_path] = "#{request.request_uri}/index"
|
78
|
+
elsif !params[:index].empty?
|
79
|
+
page_name = "#{params[:index]}/#{page_name}"
|
80
|
+
end
|
81
|
+
return page_name, page_ext
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns a path to plugin layout, if it's unspecified, otherwise
|
85
|
+
# a path to an application layout...
|
86
|
+
def get_page_layout
|
87
|
+
params[:layout]
|
88
|
+
end
|
89
|
+
|
90
|
+
# An after_filter implementing page caching if it's enabled, globally,
|
91
|
+
# and is allowed by #allow_page_cache?
|
92
|
+
def cache_cms_page
|
93
|
+
unless Comatose.config.disable_caching or response.headers['Status'] == '404 Not Found'
|
94
|
+
return unless params[:use_cache].to_s == 'true' and allow_page_cache?
|
95
|
+
path = params[:cache_path] || request.request_uri
|
96
|
+
begin
|
97
|
+
# TODO: Don't cache pages rendering '404' content...
|
98
|
+
self.class.cache_page( response.body, path )
|
99
|
+
rescue
|
100
|
+
logger.error "Comatose CMS Page Cache Exception: #{$!}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# An after_filter that sets the HTTP header for Content-Type to
|
106
|
+
# what's defined in Comatose.config.content_type. Defaults to utf-8.
|
107
|
+
def set_content_type
|
108
|
+
response.headers["Content-Type"] = "text/html; charset=#{Comatose.config.content_type}" unless Comatose.config.content_type.nil? or response.headers['Status'] == '404 Not Found'
|
109
|
+
end
|
110
|
+
|
111
|
+
COMATOSE_VIEW_PATH = File.join(RAILS_ROOT, 'vendor', 'plugins', 'comatose', 'views')
|
112
|
+
ActionController::Base.append_view_path(COMATOSE_VIEW_PATH) unless ActionController::Base.view_paths.include?(COMATOSE_VIEW_PATH)
|
113
|
+
|
114
|
+
# Include any, well, includes...
|
115
|
+
Comatose.config.includes.each do |mod|
|
116
|
+
mod_klass = if mod.is_a? String
|
117
|
+
mod.constantize
|
118
|
+
elsif mod.is_a? Symbol
|
119
|
+
mod.to_s.classify.constantize
|
120
|
+
else
|
121
|
+
mod
|
122
|
+
end
|
123
|
+
include mod_klass
|
124
|
+
end
|
125
|
+
|
126
|
+
# Include any helpers...
|
127
|
+
Comatose.config.helpers.each do |mod|
|
128
|
+
mod_klass = if mod.is_a? String
|
129
|
+
mod.constantize
|
130
|
+
elsif mod.is_a? Symbol
|
131
|
+
mod.to_s.classify.constantize
|
132
|
+
else
|
133
|
+
mod
|
134
|
+
end
|
135
|
+
helper mod_klass
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# ComatosePage attributes
|
2
|
+
# - parent_id
|
3
|
+
# - title
|
4
|
+
# - full_path
|
5
|
+
# - slug
|
6
|
+
# - keywords
|
7
|
+
# - body
|
8
|
+
# - author
|
9
|
+
# - filter_type
|
10
|
+
# - position
|
11
|
+
# - version
|
12
|
+
# - updated_on
|
13
|
+
# - created_on
|
14
|
+
class ComatosePage < ActiveRecord::Base
|
15
|
+
|
16
|
+
set_table_name 'comatose_pages'
|
17
|
+
|
18
|
+
# Only versions the content... Not all of the meta data or position
|
19
|
+
acts_as_versioned :table_name=>'comatose_page_versions', :if_changed => [:title, :slug, :keywords, :body]
|
20
|
+
|
21
|
+
define_option :active_mount_info, {:root=>'', :index=>''}
|
22
|
+
|
23
|
+
acts_as_tree :order => "position, title"
|
24
|
+
acts_as_list :scope => :parent_id
|
25
|
+
|
26
|
+
#before_create :create_full_path
|
27
|
+
before_save :cache_full_path, :create_full_path
|
28
|
+
after_save :update_children_full_path
|
29
|
+
|
30
|
+
# Using before_validation so we can default the slug from the title
|
31
|
+
before_validation do |record|
|
32
|
+
# Create slug from title
|
33
|
+
if record.slug.blank? and !record.title.blank?
|
34
|
+
record.slug = record.title.downcase.lstrip.rstrip.gsub( /[^-a-z0-9~\s\.:;+=_]/, '').gsub(/[\s\.:;=_+]+/, '-').gsub(/[\-]{2,}/, '-').to_s
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Manually set these, because record_timestamps = false
|
39
|
+
before_create do |record|
|
40
|
+
record.created_on = record.updated_on = Time.now
|
41
|
+
end
|
42
|
+
|
43
|
+
validates_presence_of :title, :on => :save, :message => "must be present"
|
44
|
+
validates_uniqueness_of :slug, :on => :save, :scope=>'parent_id', :message => "is already in use"
|
45
|
+
validates_presence_of :parent_id, :on=>:create, :message=>"must be present"
|
46
|
+
|
47
|
+
# Tests ERB/Liquid content...
|
48
|
+
validates_each :body, :allow_nil=>true, :allow_blank=>true do |record, attr, value|
|
49
|
+
begin
|
50
|
+
body_html = record.to_html
|
51
|
+
rescue SyntaxError
|
52
|
+
record.errors.add :body, "syntax error: #{$!.to_s.gsub('<', '<')}"
|
53
|
+
rescue
|
54
|
+
record.errors.add :body, "content error: #{$!.to_s.gsub('<', '<')}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns a pages URI dynamically, based on the active mount point
|
59
|
+
def uri
|
60
|
+
if full_path == ''
|
61
|
+
active_mount_info[:root]
|
62
|
+
else
|
63
|
+
page_path = (full_path || '').split('/')
|
64
|
+
idx_path = active_mount_info[:index].split('/')
|
65
|
+
uri_root = active_mount_info[:root].split('/')
|
66
|
+
uri_path = ( uri_root + (page_path - idx_path) ).flatten.delete_if {|i| i == "" }
|
67
|
+
['',uri_path].join('/')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Check if a page has a selected keyword... NOT case sensitive.
|
72
|
+
# So the keyword McCray is the same as mccray
|
73
|
+
def has_keyword?(keyword)
|
74
|
+
@key_list ||= (self.keywords || '').downcase.split(',').map {|k| k.strip }
|
75
|
+
@key_list.include? keyword.to_s.downcase
|
76
|
+
rescue
|
77
|
+
false
|
78
|
+
end
|
79
|
+
|
80
|
+
# Returns the page's content, transformed and filtered...
|
81
|
+
def to_html(options={})
|
82
|
+
#version = options.delete(:version)
|
83
|
+
text = self.body
|
84
|
+
binding = Comatose::ProcessingContext.new(self, options)
|
85
|
+
filter_type = self.filter_type || Comatose.config.default_filter
|
86
|
+
TextFilters.transform(text, binding, filter_type, Comatose.config.default_processor)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Static helpers...
|
90
|
+
|
91
|
+
# Returns a Page with a matching path.
|
92
|
+
def self.find_by_path( path )
|
93
|
+
path = path.split('.')[0] unless path.empty? # Will ignore file extension...
|
94
|
+
path = path[1..-1] if path.starts_with? "/"
|
95
|
+
find( :first, :conditions=>[ 'full_path = ?', path ] )
|
96
|
+
end
|
97
|
+
|
98
|
+
# Overrides...
|
99
|
+
|
100
|
+
# I don't want the AR magic timestamping support for this class...
|
101
|
+
def record_timestamps
|
102
|
+
false
|
103
|
+
end
|
104
|
+
def self.record_timestamps
|
105
|
+
false
|
106
|
+
end
|
107
|
+
|
108
|
+
protected
|
109
|
+
|
110
|
+
# Creates a URI path based on the Page tree
|
111
|
+
def create_full_path
|
112
|
+
if parent_node = self.parent
|
113
|
+
# Build URI Path
|
114
|
+
path = "#{parent_node.full_path}/#{self.slug}"
|
115
|
+
# strip leading space, if there is one...
|
116
|
+
path = path[1..-1] if path.starts_with? "/"
|
117
|
+
self.full_path = path || ""
|
118
|
+
else
|
119
|
+
# I'm the root -- My path is blank
|
120
|
+
self.full_path = ""
|
121
|
+
end
|
122
|
+
end
|
123
|
+
def create_full_path!
|
124
|
+
create_full_path
|
125
|
+
save
|
126
|
+
end
|
127
|
+
|
128
|
+
# Caches old path (before save) for comparison later
|
129
|
+
def cache_full_path
|
130
|
+
@old_full_path = self.full_path
|
131
|
+
end
|
132
|
+
|
133
|
+
# Updates all this content's child URI paths
|
134
|
+
def update_children_full_path(should_save=true)
|
135
|
+
# OPTIMIZE: Only update all the children if the :slug/:fullpath is different
|
136
|
+
for child in self.children
|
137
|
+
child.create_full_path! unless child.frozen?
|
138
|
+
child.update_children_full_path(should_save)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
data/lib/liquid.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# Copyright (c) 2005 Tobias Luetke
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
# a copy of this software and associated documentation files (the
|
5
|
+
# "Software"), to deal in the Software without restriction, including
|
6
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
# the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be
|
12
|
+
# included in all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOa AND
|
17
|
+
# NONINFRINGEMENT. IN NO EVENT SaALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
23
|
+
|
24
|
+
module Liquid
|
25
|
+
FilterSperator = /\|/
|
26
|
+
ArgumentSeparator = ','
|
27
|
+
FilterArgumentSeparator = ':'
|
28
|
+
VariableAttributeSeparator = '.'
|
29
|
+
TagStart = /\{\%/
|
30
|
+
TagEnd = /\%\}/
|
31
|
+
VariableStart = /\{\{/
|
32
|
+
VariableEnd = /\}\}/
|
33
|
+
AllowedVariableCharacters = /[a-zA-Z_.-]/
|
34
|
+
QuotedFragment = /"[^"]+"|'[^']+'|[^\s,|]+/
|
35
|
+
TagAttributes = /(\w+)\s*\:\s*(#{QuotedFragment})/
|
36
|
+
TokenizationRegexp = /(#{TagStart}.*?#{TagEnd}|#{VariableStart}.*?#{VariableEnd})/
|
37
|
+
end
|
38
|
+
|
39
|
+
require 'liquid/drop'
|
40
|
+
require 'liquid/extensions'
|
41
|
+
require 'liquid/errors'
|
42
|
+
require 'liquid/strainer'
|
43
|
+
require 'liquid/context'
|
44
|
+
require 'liquid/tag'
|
45
|
+
require 'liquid/block'
|
46
|
+
require 'liquid/document'
|
47
|
+
require 'liquid/variable'
|
48
|
+
require 'liquid/file_system'
|
49
|
+
require 'liquid/template'
|
50
|
+
require 'liquid/standardtags'
|
51
|
+
require 'liquid/htmltags'
|
52
|
+
require 'liquid/standardfilters'
|
data/lib/liquid/block.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
module Liquid
|
2
|
+
|
3
|
+
class Block < Tag
|
4
|
+
def parse(tokens)
|
5
|
+
@nodelist ||= []
|
6
|
+
@nodelist.clear
|
7
|
+
|
8
|
+
while token = tokens.shift
|
9
|
+
|
10
|
+
case token
|
11
|
+
when /^#{TagStart}/
|
12
|
+
if token =~ /^#{TagStart}\s*(\w+)\s*(.*)?#{TagEnd}$/
|
13
|
+
|
14
|
+
# if we found the proper block delimitor just end parsing here and let the outer block
|
15
|
+
# proceed
|
16
|
+
if block_delimiter == $1
|
17
|
+
end_tag
|
18
|
+
return
|
19
|
+
end
|
20
|
+
|
21
|
+
# fetch the tag from registered blocks
|
22
|
+
if tag = Template.tags[$1]
|
23
|
+
@nodelist << tag.new($2, tokens)
|
24
|
+
else
|
25
|
+
# this tag is not registered with the system
|
26
|
+
# pass it to the current block for special handling or error reporting
|
27
|
+
unknown_tag($1, $2, tokens)
|
28
|
+
end
|
29
|
+
else
|
30
|
+
raise SyntaxError, "Tag '#{token}' was not properly terminated with regexp: #{TagEnd.inspect} "
|
31
|
+
end
|
32
|
+
when /^#{VariableStart}/
|
33
|
+
@nodelist << create_variable(token)
|
34
|
+
when ''
|
35
|
+
# pass
|
36
|
+
else
|
37
|
+
@nodelist << token
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Make sure that its ok to end parsing in the current block.
|
42
|
+
# Effectively this method will throw and exception unless the current block is
|
43
|
+
# of type Document
|
44
|
+
assert_missing_delimitation!
|
45
|
+
end
|
46
|
+
|
47
|
+
def end_tag
|
48
|
+
end
|
49
|
+
|
50
|
+
def unknown_tag(tag, params, tokens)
|
51
|
+
case tag
|
52
|
+
when 'else'
|
53
|
+
raise SyntaxError, "#{block_name} tag does not expect else tag"
|
54
|
+
when 'end'
|
55
|
+
raise SyntaxError, "'end' is not a valid delimiter for #{block_name} tags. use #{block_delimiter}"
|
56
|
+
else
|
57
|
+
raise SyntaxError, "Unknown tag '#{tag}'"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def block_delimiter
|
62
|
+
"end#{block_name}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def block_name
|
66
|
+
self.class.name.scan(/\w+$/).first.downcase
|
67
|
+
end
|
68
|
+
|
69
|
+
def create_variable(token)
|
70
|
+
token.scan(/^#{VariableStart}(.*)#{VariableEnd}$/) do |content|
|
71
|
+
return Variable.new(content.first)
|
72
|
+
end
|
73
|
+
raise SyntaxError.new("Variable '#{token}' was not properly terminated with regexp: #{VariableEnd.inspect} ")
|
74
|
+
end
|
75
|
+
|
76
|
+
def render(context)
|
77
|
+
render_all(@nodelist, context)
|
78
|
+
end
|
79
|
+
|
80
|
+
protected
|
81
|
+
|
82
|
+
def assert_missing_delimitation!
|
83
|
+
raise SyntaxError.new("#{block_name} tag was never closed")
|
84
|
+
end
|
85
|
+
|
86
|
+
def render_all(list, context)
|
87
|
+
list.collect do |token|
|
88
|
+
if token.respond_to?(:render)
|
89
|
+
token.render(context)
|
90
|
+
else
|
91
|
+
token.to_s
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|