ruty 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|