ruty 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/ruty.rb +450 -0
- data/lib/ruty/constants.rb +23 -0
- data/lib/ruty/context.rb +148 -0
- data/lib/ruty/datastructure.rb +180 -0
- data/lib/ruty/filters.rb +188 -0
- data/lib/ruty/loaders.rb +52 -0
- data/lib/ruty/loaders/filesystem.rb +75 -0
- data/lib/ruty/parser.rb +283 -0
- data/lib/ruty/tags.rb +52 -0
- data/lib/ruty/tags/capture.rb +28 -0
- data/lib/ruty/tags/conditional.rb +59 -0
- data/lib/ruty/tags/debug.rb +28 -0
- data/lib/ruty/tags/filter.rb +27 -0
- data/lib/ruty/tags/forloop.rb +83 -0
- data/lib/ruty/tags/inclusion.rb +31 -0
- data/lib/ruty/tags/inheritance.rb +80 -0
- data/lib/ruty/tags/looptools.rb +85 -0
- metadata +65 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
# = Ruty Capture Tag
|
2
|
+
#
|
3
|
+
# Author:: Armin Ronacher
|
4
|
+
#
|
5
|
+
# Copyright (c) 2006 by Armin Ronacher
|
6
|
+
#
|
7
|
+
# You can redistribute it and/or modify it under the terms of the BSD license.
|
8
|
+
|
9
|
+
class Ruty::Tags::Capture < Ruty::Tag
|
10
|
+
|
11
|
+
def initialize parser, argstring
|
12
|
+
if not argstring =~ /^as\s+([a-zA-Z_][a-zA-Z0-9_]*)$/
|
13
|
+
parser.fail('syntax for capture tag: {% capture as <variable> %}')
|
14
|
+
end
|
15
|
+
|
16
|
+
@name = $1.to_sym
|
17
|
+
@nodelist = parser.parse_until { |n, a| n == :endcapture }
|
18
|
+
end
|
19
|
+
|
20
|
+
def render_node context, stream
|
21
|
+
substream = ''
|
22
|
+
@nodelist.render(context, substream)
|
23
|
+
context[@name] = substream
|
24
|
+
end
|
25
|
+
|
26
|
+
Ruty::Tags.register(self, :include)
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# = Ruty Conditional Tags
|
2
|
+
#
|
3
|
+
# Author:: Armin Ronacher
|
4
|
+
#
|
5
|
+
# Copyright (c) 2006 by Armin Ronacher
|
6
|
+
#
|
7
|
+
# You can redistribute it and/or modify it under the terms of the BSD license.
|
8
|
+
|
9
|
+
class Ruty::Tags::If < Ruty::Tag
|
10
|
+
|
11
|
+
def initialize parser, argstring
|
12
|
+
# parse everything until the next else or endif tag
|
13
|
+
# and save in a variable if it was a else tag for
|
14
|
+
# postprocessing.
|
15
|
+
was_else = false
|
16
|
+
@body = parser.parse_until do |name, a|
|
17
|
+
if [:endif, :else].include? name
|
18
|
+
was_else = name == :else
|
19
|
+
true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
args = parser.parse_arguments(argstring)
|
24
|
+
@else_body = parser.parse_until { |name, a| name == :endif } if was_else
|
25
|
+
|
26
|
+
if not [1, 2].include?(args.length) or \
|
27
|
+
(args.length == 2 and args[0] != :not)
|
28
|
+
parser.fail('invalid syntax for if tag')
|
29
|
+
end
|
30
|
+
|
31
|
+
@negated = args.length == 2
|
32
|
+
@item = @negated ? args[1] : args[0]
|
33
|
+
end
|
34
|
+
|
35
|
+
def render_node context, stream
|
36
|
+
item = context.resolve(@item)
|
37
|
+
if item == false
|
38
|
+
val = false
|
39
|
+
elsif item.respond_to?(:nonzero?)
|
40
|
+
val = item.nonzero?
|
41
|
+
elsif item.respond_to?(:empty?)
|
42
|
+
val = !item.empty?
|
43
|
+
elsif item.respond_to?(:size)
|
44
|
+
val = item.size > 0
|
45
|
+
elsif item.respond_to?(:length)
|
46
|
+
val = item.length > 0
|
47
|
+
else
|
48
|
+
val = !item.nil?
|
49
|
+
end
|
50
|
+
if @negated ? !val : val
|
51
|
+
@body.render_node(context, stream)
|
52
|
+
elsif @else_body
|
53
|
+
@else_body.render_node(context, stream)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
Ruty::Tags.register(self, :if)
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# = Ruty Debug Tag
|
2
|
+
#
|
3
|
+
# Author:: Armin Ronacher
|
4
|
+
#
|
5
|
+
# Copyright (c) 2006 by Armin Ronacher
|
6
|
+
#
|
7
|
+
# You can redistribute it and/or modify it under the terms of the BSD license.
|
8
|
+
|
9
|
+
require 'stringio'
|
10
|
+
require 'pp'
|
11
|
+
|
12
|
+
class Ruty::Tags::Debug < Ruty::Tag
|
13
|
+
|
14
|
+
def initialize parser, argstring
|
15
|
+
parser.fail('debug tag takes no arguments') if not argstring.empty?
|
16
|
+
end
|
17
|
+
|
18
|
+
def render_node context, stream
|
19
|
+
buffer = StringIO.new
|
20
|
+
PP.pp(context, buffer)
|
21
|
+
buffer.rewind
|
22
|
+
stream << buffer.read.strip
|
23
|
+
buffer.close
|
24
|
+
end
|
25
|
+
|
26
|
+
Ruty::Tags.register(self, :debug)
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# = Ruty Filter Tag
|
2
|
+
#
|
3
|
+
# Author:: Armin Ronacher
|
4
|
+
#
|
5
|
+
# Copyright (c) 2006 by Armin Ronacher
|
6
|
+
#
|
7
|
+
# You can redistribute it and/or modify it under the terms of the BSD license.
|
8
|
+
|
9
|
+
class Ruty::Tags::Filter < Ruty::Tag
|
10
|
+
|
11
|
+
def initialize parser, argstring
|
12
|
+
@filters = parser.parse_arguments('|' + argstring)
|
13
|
+
parser.fail('filter tag requires at least on filter') if @filters.empty?
|
14
|
+
@nodelist = parser.parse_until { |n, a| n == :endfilter }
|
15
|
+
end
|
16
|
+
|
17
|
+
def render_node context, stream
|
18
|
+
substream = Ruty::Datastructure::OutputStream.new
|
19
|
+
@nodelist.render_node(context, substream)
|
20
|
+
value = context.apply_filters(substream.to_s, @filters).to_s
|
21
|
+
stream << value if not value.empty?
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
|
25
|
+
Ruty::Tags.register(self, :filter)
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# = Ruty For Loop Tag
|
2
|
+
#
|
3
|
+
# Author:: Armin Ronacher
|
4
|
+
#
|
5
|
+
# Copyright (c) 2006 by Armin Ronacher
|
6
|
+
#
|
7
|
+
# You can redistribute it and/or modify it under the terms of the BSD license.
|
8
|
+
|
9
|
+
class Ruty::Tags::ForLoop < Ruty::Tag
|
10
|
+
|
11
|
+
def initialize parser, argstring
|
12
|
+
# parse everything until the next else or endfor tag
|
13
|
+
# and save in a variable if it was a else tag or an
|
14
|
+
# endfor tag so that we can parse the second part if
|
15
|
+
# required later.
|
16
|
+
was_else = false
|
17
|
+
@body = parser.parse_until do |name, a|
|
18
|
+
if [:endfor, :else].include? name
|
19
|
+
was_else = name == :else
|
20
|
+
true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
args = parser.parse_arguments(argstring)
|
25
|
+
@else_body = parser.parse_until { |name, a| name == :endfor } if was_else
|
26
|
+
if args.length != 3 or args[1] != :in
|
27
|
+
parser.fail('invalid syntax for for-loop tag')
|
28
|
+
end
|
29
|
+
@item = args[0]
|
30
|
+
@iterable = args[2]
|
31
|
+
end
|
32
|
+
|
33
|
+
def render_node context, stream
|
34
|
+
iterable = context.resolve(@iterable)
|
35
|
+
length = 0
|
36
|
+
if iterable.respond_to?(:each)
|
37
|
+
if iterable.respond_to?(:size)
|
38
|
+
length = iterable.size
|
39
|
+
elsif iterable.respond_to?(:length)
|
40
|
+
length = iterable.length
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
if length > 0
|
45
|
+
index = 0
|
46
|
+
parent = context[:loop]
|
47
|
+
context.push
|
48
|
+
|
49
|
+
iterable.each do |item|
|
50
|
+
break if index == length
|
51
|
+
context[@item] = item
|
52
|
+
context[:loop] = {
|
53
|
+
:parent => parent,
|
54
|
+
:index => index + 1,
|
55
|
+
:index0 => index,
|
56
|
+
:revindex => length - index,
|
57
|
+
:revindex0 => length - index - 1,
|
58
|
+
:first => index == 0,
|
59
|
+
:last => length - index == 1,
|
60
|
+
:length => length,
|
61
|
+
:even => index % 2 != 0,
|
62
|
+
:odd => index % 2 == 0
|
63
|
+
}
|
64
|
+
@body.render_node(context, stream)
|
65
|
+
index += 1
|
66
|
+
end
|
67
|
+
if index != 0
|
68
|
+
context.pop
|
69
|
+
return nil
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# if we reach this point there was no iteration. either because
|
74
|
+
# we tried to iterate something without a size or it was an object
|
75
|
+
# that isn't iterable, render the else_body if given
|
76
|
+
@else_body.render_node(context, stream) if @else_body
|
77
|
+
context.pop
|
78
|
+
nil
|
79
|
+
end
|
80
|
+
|
81
|
+
Ruty::Tags.register(self, :for)
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# = Ruty Include Tags
|
2
|
+
#
|
3
|
+
# Author:: Armin Ronacher
|
4
|
+
#
|
5
|
+
# Copyright (c) 2006 by Armin Ronacher
|
6
|
+
#
|
7
|
+
# You can redistribute it and/or modify it under the terms of the BSD license.
|
8
|
+
|
9
|
+
# simple include tag. just includes another template at
|
10
|
+
# the current position. (for header/footer inclusion for
|
11
|
+
# example, although it's better to use extends in combination
|
12
|
+
# with some blocks)
|
13
|
+
class Ruty::Tags::Include < Ruty::Tag
|
14
|
+
|
15
|
+
def initialize parser, argstring
|
16
|
+
if not argstring =~ /^("')(.*?)\1$/
|
17
|
+
parser.fail('include takes exactly one argument which must be ' +
|
18
|
+
'an hardcoded string')
|
19
|
+
end
|
20
|
+
|
21
|
+
# load given template using the load_local function of the parser
|
22
|
+
@nodelist = parser.load_local(argstring[1...-1])
|
23
|
+
end
|
24
|
+
|
25
|
+
def render_node context, stream
|
26
|
+
@nodelist.render_node(context, stream)
|
27
|
+
end
|
28
|
+
|
29
|
+
Ruty::Tags.register(self, :include)
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# = Ruty Template Inheritance
|
2
|
+
#
|
3
|
+
# Author:: Armin Ronacher
|
4
|
+
#
|
5
|
+
# Copyright (c) 2006 by Armin Ronacher
|
6
|
+
#
|
7
|
+
# You can redistribute it and/or modify it under the terms of the BSD license.
|
8
|
+
|
9
|
+
# special tag that marks a part of a template for inheritance.
|
10
|
+
# If a template extends from a template with a block tag with
|
11
|
+
# the same name it will replace the block in the inherited
|
12
|
+
# template with the block with the same name in the current
|
13
|
+
# template.
|
14
|
+
class Ruty::Tags::Block < Ruty::Tag
|
15
|
+
|
16
|
+
def initialize parser, argstring
|
17
|
+
if not argstring =~ /^[a-zA-Z_][a-zA-Z0-9_]*$/
|
18
|
+
parser.fail('Invalid syntax for block tag')
|
19
|
+
end
|
20
|
+
@name = argstring.to_sym
|
21
|
+
@stack = [parser.parse_until { |name, a| name == :endblock }]
|
22
|
+
|
23
|
+
blocks = (parser.storage[:blocks] ||= {})
|
24
|
+
parser.fail("block '#{@name}' defined twice") if blocks.include?(@name)
|
25
|
+
blocks[@name] = self
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_layer nodelist
|
29
|
+
@stack << nodelist
|
30
|
+
end
|
31
|
+
|
32
|
+
def render_node context, stream, index=-1
|
33
|
+
context.push
|
34
|
+
context[:block] = Ruty::Datastructure::Deferred.new(
|
35
|
+
:super => Proc.new {
|
36
|
+
render_node(context, stream, index - 1) if index.abs <= @stack.size
|
37
|
+
},
|
38
|
+
:depth => Proc.new { index.abs },
|
39
|
+
:name => Proc.new { @name }
|
40
|
+
)
|
41
|
+
@stack[index].render_node(context, stream)
|
42
|
+
context.pop
|
43
|
+
nil
|
44
|
+
end
|
45
|
+
|
46
|
+
Ruty::Tags.register(self, :block)
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
# tag used to load a template from another file. must be the first
|
51
|
+
# tag of a document!
|
52
|
+
class Ruty::Tags::Extends < Ruty::Tag
|
53
|
+
|
54
|
+
def initialize parser, argstring
|
55
|
+
if not parser.first
|
56
|
+
parser.fail('extends tag must be at the beginning of a template')
|
57
|
+
elsif not argstring =~ /^(["'])(.*?)\1$/
|
58
|
+
parser.fail('extends takes exactly one argument which must be ' +
|
59
|
+
'an hardcoded string')
|
60
|
+
end
|
61
|
+
|
62
|
+
# parse the template to the end and load parent nodelist
|
63
|
+
parser.parse_all
|
64
|
+
@nodelist = parser.load_local(argstring[1...-1])
|
65
|
+
blocks = @nodelist.parser.storage[:blocks] || {}
|
66
|
+
|
67
|
+
# iterate over all blocks found while parsing and add them
|
68
|
+
# to the parent nodelist which will be the new nodelist
|
69
|
+
(parser.storage[:blocks] || []).each do |name, tag|
|
70
|
+
blocks[name].add_layer(tag) if blocks.include?(name)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def render_node context, stream
|
75
|
+
@nodelist.render_node(context, stream)
|
76
|
+
end
|
77
|
+
|
78
|
+
Ruty::Tags.register(self, :extends)
|
79
|
+
|
80
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# = Ruty Loop Tool Tags
|
2
|
+
#
|
3
|
+
# Author:: Armin Ronacher
|
4
|
+
#
|
5
|
+
# Copyright (c) 2006 by Armin Ronacher
|
6
|
+
#
|
7
|
+
# You can redistribute it and/or modify it under the terms of the BSD license.
|
8
|
+
|
9
|
+
# A tag that cycles through a list of values each iteration
|
10
|
+
# Useful for example if you want alternating rows:
|
11
|
+
#
|
12
|
+
# {% for row in rows %}
|
13
|
+
# <tr class="{% cycle 'row1', 'row2' %}">
|
14
|
+
# <td>..</td>
|
15
|
+
# </tr>
|
16
|
+
# {% endfor %}
|
17
|
+
class Ruty::Tags::Cycle < Ruty::Tag
|
18
|
+
|
19
|
+
def initialize parser, argstring
|
20
|
+
args = parser.parse_arguments(argstring)
|
21
|
+
parser.fail('At least one item is required for cycle') if args.empty?
|
22
|
+
@items = args
|
23
|
+
end
|
24
|
+
|
25
|
+
def render_node context, stream
|
26
|
+
item = @items[context[self] = ((context[self] || -1) + 1) % @items.length]
|
27
|
+
item = context.resolve(item) if item.is_a?(Symbol)
|
28
|
+
stream << item.to_s
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
|
32
|
+
Ruty::Tags.register(self, :cycle)
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
# just render everything between the tag and the closing
|
38
|
+
# endifchanged tag if the given variable hasn't changed
|
39
|
+
# from the last iteration. If no variable is given the
|
40
|
+
# block will check it's own rendering against the
|
41
|
+
# rendering of the last iteration.
|
42
|
+
#
|
43
|
+
# {% for day in days %}
|
44
|
+
# <div class="day">
|
45
|
+
# <h2>{{ day.name|escape }}</h2>
|
46
|
+
# {% for entry in day.entries %}
|
47
|
+
# {% ifchanged entry.pub_date.hour %}
|
48
|
+
# <h3>{{ entry.pub_date }}</h3>
|
49
|
+
# {% endifchanged %}
|
50
|
+
# ...
|
51
|
+
# {% endfor %}
|
52
|
+
# </div>
|
53
|
+
# {% endfor %}
|
54
|
+
class Ruty::Tags::IfChanged < Ruty::Tag
|
55
|
+
|
56
|
+
def initialize parser, argstring
|
57
|
+
args = parser.parse_arguments(argstring)
|
58
|
+
if not [0, 1].include?(args.length)
|
59
|
+
parser.fail('ifchanged-tag takes at most one argument')
|
60
|
+
end
|
61
|
+
@arg = args[0]
|
62
|
+
@body = parser.parse_until { |name, a| name == :endifchanged }
|
63
|
+
end
|
64
|
+
|
65
|
+
def render_node context, stream
|
66
|
+
if not @arg
|
67
|
+
substream = Datastructure::OutputStream.new
|
68
|
+
@body.render_node(context, substream)
|
69
|
+
this_iteration = substream.to_s
|
70
|
+
if this_iteration != context[self]
|
71
|
+
block << this_iteration
|
72
|
+
context[self] = this_iteration
|
73
|
+
end
|
74
|
+
else
|
75
|
+
item = (@arg.is_a?(Symbol)) ? context.resolve(@arg) : @arg
|
76
|
+
if item != context[self]
|
77
|
+
@body.render_node(context, stream)
|
78
|
+
context[self] = item
|
79
|
+
end
|
80
|
+
end
|
81
|
+
nil
|
82
|
+
end
|
83
|
+
|
84
|
+
Ruty::Tags.register(self, :ifchanged)
|
85
|
+
end
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.0
|
3
|
+
specification_version: 1
|
4
|
+
name: ruty
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.0.1
|
7
|
+
date: 2007-01-21 00:00:00 +01:00
|
8
|
+
summary: A Template-Engine inspired by the jinja engine
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email:
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: "true"
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Armin Ronacher
|
31
|
+
files:
|
32
|
+
- lib/ruty
|
33
|
+
- lib/ruty.rb
|
34
|
+
- lib/ruty/constants.rb
|
35
|
+
- lib/ruty/context.rb
|
36
|
+
- lib/ruty/datastructure.rb
|
37
|
+
- lib/ruty/filters.rb
|
38
|
+
- lib/ruty/loaders
|
39
|
+
- lib/ruty/loaders.rb
|
40
|
+
- lib/ruty/parser.rb
|
41
|
+
- lib/ruty/tags
|
42
|
+
- lib/ruty/tags.rb
|
43
|
+
- lib/ruty/loaders/filesystem.rb
|
44
|
+
- lib/ruty/tags/capture.rb
|
45
|
+
- lib/ruty/tags/conditional.rb
|
46
|
+
- lib/ruty/tags/debug.rb
|
47
|
+
- lib/ruty/tags/filter.rb
|
48
|
+
- lib/ruty/tags/forloop.rb
|
49
|
+
- lib/ruty/tags/inclusion.rb
|
50
|
+
- lib/ruty/tags/inheritance.rb
|
51
|
+
- lib/ruty/tags/looptools.rb
|
52
|
+
test_files: []
|
53
|
+
|
54
|
+
rdoc_options: []
|
55
|
+
|
56
|
+
extra_rdoc_files: []
|
57
|
+
|
58
|
+
executables: []
|
59
|
+
|
60
|
+
extensions: []
|
61
|
+
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
dependencies: []
|
65
|
+
|