radius 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/DSL-SPEC +151 -0
- data/QUICKSTART +98 -0
- data/README +49 -0
- data/ROADMAP +18 -0
- data/Rakefile +41 -0
- data/lib/radius.rb +126 -0
- data/test/radius_test.rb +122 -0
- metadata +55 -0
data/DSL-SPEC
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
=DSL Specification
|
2
|
+
|
3
|
+
I haven't implemented a domain specific languages for Contexts yet, but I am hoping to
|
4
|
+
do so in a future release. Below are some thoughts (in code) for how I would like it to
|
5
|
+
work. Note that with a robust DSL you will be able to define that certain tags are
|
6
|
+
only valid within certain containing tags.
|
7
|
+
|
8
|
+
class StoreContext < Radius::Context
|
9
|
+
def initialize(options)
|
10
|
+
@prefix = "r" # all tags must be prefixed with "r"
|
11
|
+
@user = options[:user]
|
12
|
+
@cart = options[:cart]
|
13
|
+
@session = options[:session]
|
14
|
+
end
|
15
|
+
|
16
|
+
# expose the @user object variable
|
17
|
+
container(:user, :exposes => :user) do
|
18
|
+
# Use protect() on an object that has been exposed to prevent access to
|
19
|
+
# an attribute in a template. Conversely you could use the expose() method
|
20
|
+
# to expose specific attributes to the template and protect all others.
|
21
|
+
protect :password
|
22
|
+
|
23
|
+
# add a single tag that returns the session_id
|
24
|
+
tag :session_id do |attributes|
|
25
|
+
@session.id
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# expose the @cart object as the basket tag
|
30
|
+
container(:basket, :exposes => :cart) do
|
31
|
+
expand do |attributes|
|
32
|
+
#
|
33
|
+
# some initialization code with attributes before handling
|
34
|
+
# content block
|
35
|
+
#
|
36
|
+
yeild
|
37
|
+
end
|
38
|
+
|
39
|
+
container(:items, :exposes => :item) do
|
40
|
+
expand do |attributes|
|
41
|
+
@cart.items.each do |@item|
|
42
|
+
yield
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
container :cart do
|
49
|
+
expand do |attributes|
|
50
|
+
yield
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class User
|
56
|
+
attr_accessor :name, :login, :password, :email
|
57
|
+
def initialize(name, login, password, email)
|
58
|
+
@name, @login, @password, @email = name, login, password, email
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class Session
|
63
|
+
attr_accessor :id
|
64
|
+
def initialize(id)
|
65
|
+
@id = id
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class Cart
|
70
|
+
attr_accessor :items
|
71
|
+
|
72
|
+
def initialize(*items)
|
73
|
+
@items = [items].flatten
|
74
|
+
end
|
75
|
+
|
76
|
+
def total
|
77
|
+
@items.map { |line_item| line_item.total }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class LineItem
|
82
|
+
attr_accessor :name, :description, :quantity, :item_price
|
83
|
+
def intialize(name, description, price, quantity)
|
84
|
+
@name, @description, @price, @quantity = name, description, price, quantity
|
85
|
+
end
|
86
|
+
def full_price
|
87
|
+
@price * @quantity
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
receipt = <<-RECEIPT
|
92
|
+
<p><r:user:name />, thank you for shopping with us! An order summary
|
93
|
+
is printed below for your convinience. Please print a copy for your records.</p>
|
94
|
+
<r:cart>
|
95
|
+
<table>
|
96
|
+
<thead>
|
97
|
+
<tr>
|
98
|
+
<td>Product</td>
|
99
|
+
<td>Price</td>
|
100
|
+
<td>Quantity</td>
|
101
|
+
<td>Totals</td>
|
102
|
+
</tr>
|
103
|
+
</thead>
|
104
|
+
<tbody>
|
105
|
+
<r:items>
|
106
|
+
<tr>
|
107
|
+
<td>
|
108
|
+
<strong><r:name /></strong><br >
|
109
|
+
<r:description />
|
110
|
+
</td>
|
111
|
+
<td><r:price /></td>
|
112
|
+
<td><r:quanity /></td>
|
113
|
+
<td><r:full_price /></td>
|
114
|
+
</tr>
|
115
|
+
</r:items>
|
116
|
+
</tbody>
|
117
|
+
<tr>
|
118
|
+
<td colspan="3">Total</td>
|
119
|
+
<td><r:total /></td>
|
120
|
+
</tr>
|
121
|
+
</table>
|
122
|
+
</r:cart>
|
123
|
+
RECEIPT
|
124
|
+
|
125
|
+
user = User.new('John', 'johnboy', 'm@x!mu5', 'johnboy@maximus.com')
|
126
|
+
cart = Cart.new(
|
127
|
+
LineItem.new('15in PowerBook', "Apple's premium notebook computer.", 1995.98, 1),
|
128
|
+
LineItem.new('Mac Notebook Case', "A beautiful black notebook case designed for Apple Powerbooks.", 54.05, 1)
|
129
|
+
)
|
130
|
+
session = Session.new('a4bd386e512bacd581')
|
131
|
+
|
132
|
+
context = StoreContext.new(
|
133
|
+
:user => user,
|
134
|
+
:cart => cart,
|
135
|
+
:session => session
|
136
|
+
)
|
137
|
+
|
138
|
+
template = Radius::Template.new(
|
139
|
+
:text => receipt,
|
140
|
+
:context => context
|
141
|
+
)
|
142
|
+
|
143
|
+
template.compile! # based on context parses text into abstract syntax tree
|
144
|
+
puts template.expand # outputs expanded template
|
145
|
+
|
146
|
+
# alternate usage
|
147
|
+
parser = Radius::Parser.new(context)
|
148
|
+
puts parser.parse(receipt) # compiles and outputs expanded template
|
149
|
+
|
150
|
+
# another alternate
|
151
|
+
puts Radius.parse(receipt, context)
|
data/QUICKSTART
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
=Quick Start
|
2
|
+
|
3
|
+
Before you can parse a template with Radius you need to create a Context object which defines
|
4
|
+
the tags that will be used in the template. This is pretty simple:
|
5
|
+
|
6
|
+
require 'radius'
|
7
|
+
|
8
|
+
class MyContext < Radius::Context
|
9
|
+
def hello(attr)
|
10
|
+
"Hello #{attr['name'] || 'World'}!"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
Once you have defined a context you can create a Parser and parse to your heart's content:
|
15
|
+
|
16
|
+
parser = Radius::Parser.new(MyContext.new)
|
17
|
+
puts parser.parse('<p><radius:hello /></p>')
|
18
|
+
puts parser.parse('<p><radius:hello name="John" /></p>')
|
19
|
+
|
20
|
+
This will output:
|
21
|
+
|
22
|
+
<p>Hello World!</p>
|
23
|
+
<p>Hello John!</p>
|
24
|
+
|
25
|
+
Note how you can pass attributes from the template to the context using the attributes hash
|
26
|
+
(which is passed in as the first parameter.). Above the first tag that was parsed didn't have
|
27
|
+
a name attribute so the code in the +hello+ method uses "World" instead. The second time the
|
28
|
+
tag is parsed the name attribute is set to "John" which is used to create the string "Hello
|
29
|
+
John!".
|
30
|
+
|
31
|
+
Radius also allows you to define "container" tags. That is, tags that contain content and
|
32
|
+
that may optionally manipulate it in some way. For example, if you have RedCloth installed
|
33
|
+
you could define another tag to parse and create Textile output:
|
34
|
+
|
35
|
+
require 'redcloth'
|
36
|
+
|
37
|
+
class MyContext < Radius::Context
|
38
|
+
def textile(attr)
|
39
|
+
contents = yield
|
40
|
+
RedCloth.new(contents).to_html
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
With the code above your parser can easily handle Textile:
|
45
|
+
|
46
|
+
parser.parse('<radius:textile>h1. Hello **World**!</radius:textile>')
|
47
|
+
|
48
|
+
This will output:
|
49
|
+
|
50
|
+
<h1>Hello <strong>World</strong>!</h1>
|
51
|
+
|
52
|
+
But wait!--it gets better. Because container tags can manipulate what they contain you can use
|
53
|
+
them to iterate over collections:
|
54
|
+
|
55
|
+
class ThreeStoogesContext < Radius::Context
|
56
|
+
def initialize
|
57
|
+
@prefix = 'ts'
|
58
|
+
end
|
59
|
+
def stooge(attr)
|
60
|
+
content = ''
|
61
|
+
["Larry", "Moe", "Curly"].each do |name|
|
62
|
+
@name = name
|
63
|
+
content << yield
|
64
|
+
end
|
65
|
+
content
|
66
|
+
end
|
67
|
+
def name(attr)
|
68
|
+
@name
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
parser = Radius::Parser.new(ThreeStoogesContext.new)
|
73
|
+
|
74
|
+
template = <<-TEMPLATE
|
75
|
+
<ul>
|
76
|
+
<ts:stooge>
|
77
|
+
<li><ts:name /></li>
|
78
|
+
</ts:stooge>
|
79
|
+
</ul>
|
80
|
+
TEMPLATE
|
81
|
+
|
82
|
+
puts parser.parse(template)
|
83
|
+
|
84
|
+
This will output:
|
85
|
+
|
86
|
+
<ul>
|
87
|
+
|
88
|
+
<li>Larry</li>
|
89
|
+
|
90
|
+
<li>Moe</li>
|
91
|
+
|
92
|
+
<li>Curly</li>
|
93
|
+
|
94
|
+
</ul>
|
95
|
+
|
96
|
+
The above code also illustrates how you can set the prefix instance variable to control the
|
97
|
+
string that prefixes Radius tags. By setting the prefix to "ts" our tags must begin with "ts"
|
98
|
+
instead of "radius" like they did in the other examples.
|
data/README
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
= Radius -- Powerful Tag-Based Templates
|
2
|
+
|
3
|
+
Radius is a small, but powerful template language for Ruby inspired by the template languages
|
4
|
+
used in MovableType <http://www.movabletype.org> and TextPattern <http://www.textpattern.com>.
|
5
|
+
It uses tags similar to HTML, but can be used to generate any form of plain text (XML, e-mail,
|
6
|
+
etc...).
|
7
|
+
|
8
|
+
|
9
|
+
== Download
|
10
|
+
|
11
|
+
The latest version of Radius can be found on RubyForge:
|
12
|
+
|
13
|
+
http://rubyforge.org/projects/radius/
|
14
|
+
|
15
|
+
|
16
|
+
== Installation
|
17
|
+
|
18
|
+
It is recommended that you install Radius using the RubyGems packaging system:
|
19
|
+
|
20
|
+
% gem install --remote radius
|
21
|
+
|
22
|
+
You can also install Radius by copying radius.rb into the Ruby load path.
|
23
|
+
|
24
|
+
== License
|
25
|
+
|
26
|
+
Radius is free software and may be redistributed under the same terms and Ruby itself. For
|
27
|
+
more details, see the readme file in the Ruby distribution.
|
28
|
+
|
29
|
+
|
30
|
+
== Quick Start
|
31
|
+
|
32
|
+
To get up and running fast with Radius read:
|
33
|
+
|
34
|
+
link:files/QUICKSTART.html
|
35
|
+
|
36
|
+
|
37
|
+
== A Call to Action
|
38
|
+
|
39
|
+
Radius is still very much in the development stages. Take a look at the roadmap to see where
|
40
|
+
we want to go:
|
41
|
+
|
42
|
+
link:files/ROADMAP.html
|
43
|
+
|
44
|
+
If you are a smart developer with a passion for excellence, now is the time to jump on board.
|
45
|
+
Contact me and we'll talk. :)
|
46
|
+
|
47
|
+
--
|
48
|
+
|
49
|
+
John Long :: http://wiseheartdesign.com
|
data/ROADMAP
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
= Roadmap
|
2
|
+
|
3
|
+
This is a prioritized roadmap for future releases:
|
4
|
+
|
5
|
+
1. Clean up the current code base.
|
6
|
+
|
7
|
+
2. Add support for multi-level contexts: tags should be able to be
|
8
|
+
defined to only be valid within other sets of tags.
|
9
|
+
|
10
|
+
3. Create a simple DSL for defining contexts. I had done some thinking
|
11
|
+
about this in the past. This thread on Ruby-Talk defined part of it:
|
12
|
+
|
13
|
+
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/127640/
|
14
|
+
|
15
|
+
Update: See link:files/DSL-SPEC.html for a fuller explanation of how
|
16
|
+
the DSL should behave.
|
17
|
+
|
18
|
+
4. Optimize for speed. Incorporate strscan?
|
data/Rakefile
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
Rake::TestTask.new do |t|
|
9
|
+
t.pattern = 'test/**/*_test.rb'
|
10
|
+
end
|
11
|
+
|
12
|
+
Rake::RDocTask.new do |rd|
|
13
|
+
rd.title = 'Radius -- Powerful Tag-Based Templates'
|
14
|
+
rd.main = "README"
|
15
|
+
rd.rdoc_files.include("README", "QUICKSTART", "ROADMAP", "DSL-SPEC", "lib/**/*.rb")
|
16
|
+
rd.rdoc_dir = 'doc'
|
17
|
+
end
|
18
|
+
|
19
|
+
spec = Gem::Specification.new do |s|
|
20
|
+
s.platform = Gem::Platform::RUBY
|
21
|
+
s.summary = "Powerful tag-based template system."
|
22
|
+
s.name = 'radius'
|
23
|
+
s.version = '0.0.1'
|
24
|
+
s.requirements << 'none'
|
25
|
+
s.require_path = 'lib'
|
26
|
+
s.autorequire = 'radius'
|
27
|
+
s.has_rdoc = true
|
28
|
+
s.rdoc_options << '--title' << 'Radius -- Powerful Tag-Based Templates' <<
|
29
|
+
'--main' << 'README' <<
|
30
|
+
'--line-numbers' << 'ROADMAP' <<
|
31
|
+
'QUICKSTART' << 'DSL-SPEC' << 'README'
|
32
|
+
files = FileList['**/*']
|
33
|
+
files.exclude 'doc'
|
34
|
+
s.files = files.to_a
|
35
|
+
s.description = "Radius is a small, but powerful tag-based template language inspired\nby the template languages used in MovableType and TextPattern."
|
36
|
+
end
|
37
|
+
|
38
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
39
|
+
pkg.need_zip = true
|
40
|
+
pkg.need_tar = true
|
41
|
+
end
|
data/lib/radius.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
module Radius
|
2
|
+
class ParseError < StandardError # :nodoc:
|
3
|
+
end
|
4
|
+
|
5
|
+
class MissingEndTagError < ParseError # :nodoc:
|
6
|
+
def initialize(tag_name)
|
7
|
+
super("end tag not found for start tag `#{tag_name}'")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
#
|
12
|
+
# An abstract class for creating a Context. A context defines the tags that
|
13
|
+
# are available for use in a template.
|
14
|
+
#
|
15
|
+
class Context
|
16
|
+
# The prefix attribute controls the string of text that is helps the parser
|
17
|
+
# identify template tags. By default this attribute is set to "radius", but
|
18
|
+
# you may want to override this for your own contexts.
|
19
|
+
attr_accessor :prefix
|
20
|
+
|
21
|
+
# Creates a new Context object.
|
22
|
+
def initialize
|
23
|
+
@prefix = 'radius'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Tag # :nodoc:
|
28
|
+
def initialize(&b)
|
29
|
+
@block = b
|
30
|
+
end
|
31
|
+
def on_parse(&b)
|
32
|
+
@block = b
|
33
|
+
end
|
34
|
+
def to_s
|
35
|
+
@block.call(self)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class ContainerTag < Tag # :nodoc:
|
40
|
+
attr_accessor :name, :attributes, :contents
|
41
|
+
|
42
|
+
def initialize(name="", attributes={}, contents=[], &b)
|
43
|
+
@name, @attributes, @contents = name, attributes, contents
|
44
|
+
super(&b)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# The Radius parser. Initialize a parser with the Context object that defines
|
50
|
+
# how tags should be expanded.
|
51
|
+
#
|
52
|
+
class Parser
|
53
|
+
# The Context object used to expand template tags.
|
54
|
+
attr_accessor :context
|
55
|
+
|
56
|
+
# Creates a new parser object initialized with a context.
|
57
|
+
def initialize(context = Context.new)
|
58
|
+
@context = context
|
59
|
+
end
|
60
|
+
|
61
|
+
# Parse string for tags, expand them, and return the result.
|
62
|
+
def parse(string)
|
63
|
+
@stack = [ContainerTag.new { |t| t.contents.to_s }]
|
64
|
+
pre_parse(string)
|
65
|
+
@stack.last.to_s
|
66
|
+
end
|
67
|
+
|
68
|
+
def pre_parse(text) # :nodoc:
|
69
|
+
re = %r{<#{@context.prefix}:(\w+?)(?:\s+?([^/>]*?)|)>|</#{@context.prefix}:(\w+?)\s*?>}
|
70
|
+
if md = re.match(text)
|
71
|
+
start_tag, attr, end_tag = $1, $2, $3
|
72
|
+
@stack.last.contents << Tag.new { parse_individual(md.pre_match) }
|
73
|
+
remaining = md.post_match
|
74
|
+
if start_tag
|
75
|
+
parse_start_tag(start_tag, attr, remaining)
|
76
|
+
else
|
77
|
+
parse_end_tag(end_tag, remaining)
|
78
|
+
end
|
79
|
+
else
|
80
|
+
if @stack.length == 1
|
81
|
+
@stack.last.contents << Tag.new { parse_individual(text) }
|
82
|
+
else
|
83
|
+
raise MissingEndTagError.new(@stack.last.name)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def parse_start_tag(start_tag, attr, remaining) # :nodoc:
|
89
|
+
@stack.push(ContainerTag.new(start_tag, parse_attributes(attr)))
|
90
|
+
pre_parse(remaining)
|
91
|
+
end
|
92
|
+
|
93
|
+
def parse_end_tag(end_tag, remaining) # :nodoc:
|
94
|
+
popped = @stack.pop
|
95
|
+
if popped.name == end_tag
|
96
|
+
popped.on_parse { |t| @context.send(popped.name, popped.attributes) { t.contents.to_s } }
|
97
|
+
tag = @stack.last
|
98
|
+
tag.contents << popped
|
99
|
+
pre_parse(remaining)
|
100
|
+
else
|
101
|
+
raise MissingEndTagError.new(popped.name)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def parse_individual(text) # :nodoc:
|
106
|
+
re = /<#{@context.prefix}:(\w+?)\s+?(.*?)\s*?\/>/
|
107
|
+
if md = re.match(text)
|
108
|
+
attr = parse_attributes($2)
|
109
|
+
replace = @context.send($1, attr)
|
110
|
+
md.pre_match + replace + parse_individual(md.post_match)
|
111
|
+
else
|
112
|
+
text || ''
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def parse_attributes(text) # :nodoc:
|
117
|
+
attr = {}
|
118
|
+
re = /(\w+?)\s*=\s*('|")(.*?)\2/
|
119
|
+
while md = re.match(text)
|
120
|
+
attr[$1] = $3
|
121
|
+
text = md.post_match
|
122
|
+
end
|
123
|
+
attr
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/test/radius_test.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'radius'
|
3
|
+
|
4
|
+
class ContextTest < Test::Unit::TestCase
|
5
|
+
def test_initialize
|
6
|
+
c = Radius::Context.new
|
7
|
+
assert_equal 'radius', c.prefix
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class RadiusTest < Test::Unit::TestCase
|
12
|
+
class TestContext < Radius::Context
|
13
|
+
def initialize
|
14
|
+
@prefix = "test"
|
15
|
+
@items = ["Larry", "Moe", "Curly"]
|
16
|
+
end
|
17
|
+
|
18
|
+
def echo(attr)
|
19
|
+
attr["text"]
|
20
|
+
end
|
21
|
+
|
22
|
+
def add(attr)
|
23
|
+
(attr["param1"].to_i + attr["param2"].to_i).to_s
|
24
|
+
end
|
25
|
+
|
26
|
+
def reverse(attr)
|
27
|
+
yield.reverse
|
28
|
+
end
|
29
|
+
|
30
|
+
def capitalize(attr)
|
31
|
+
yield.upcase
|
32
|
+
end
|
33
|
+
|
34
|
+
def count(attr)
|
35
|
+
case
|
36
|
+
when attr["set"]
|
37
|
+
@count = attr["set"].to_i
|
38
|
+
""
|
39
|
+
when attr["inc"] == "true"
|
40
|
+
@count = (@count || 0) + 1
|
41
|
+
""
|
42
|
+
else
|
43
|
+
@count.to_s
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def loop(attr)
|
48
|
+
t = attr["times"].to_i
|
49
|
+
result = ""
|
50
|
+
t.times { result += yield }
|
51
|
+
result
|
52
|
+
end
|
53
|
+
|
54
|
+
def each_item(attr)
|
55
|
+
result = []
|
56
|
+
@items.each { |@item| result << yield }
|
57
|
+
@item = nil
|
58
|
+
result.join(attr["between"] || "")
|
59
|
+
end
|
60
|
+
|
61
|
+
def item(attr)
|
62
|
+
@item
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def setup
|
67
|
+
@t = Radius::Parser.new(TestContext.new )
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_parse_individual
|
71
|
+
r = @t.parse_individual(%{<<test:echo text="hello world!" />>})
|
72
|
+
assert_equal("<hello world!>", r)
|
73
|
+
|
74
|
+
r = @t.parse_individual(%{<test:add param1="1" param2='2'/>})
|
75
|
+
assert_equal("3", r)
|
76
|
+
|
77
|
+
r = @t.parse_individual(%{a <test:echo text="3 + 1 =" /> <test:add param1="3" param2="1"/> b})
|
78
|
+
assert_equal("a 3 + 1 = 4 b", r)
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_parse_attributes
|
82
|
+
r = @t.parse_attributes(%{ a="1" b='2'c="3"d="'" })
|
83
|
+
assert_equal({"a" => "1", "b" => "2", "c" => "3", "d" => "'"}, r)
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_parse
|
87
|
+
r = @t.parse(%{<<test:echo text="hello world!" />>})
|
88
|
+
assert_equal("<hello world!>", r)
|
89
|
+
|
90
|
+
r = @t.parse("<test:reverse>test</test:reverse>")
|
91
|
+
assert_equal("test".reverse, r)
|
92
|
+
|
93
|
+
r = @t.parse("<test:reverse>test</test:reverse> <test:capitalize>test</test:capitalize>")
|
94
|
+
assert_equal("tset TEST", r)
|
95
|
+
|
96
|
+
r = @t.parse("<test:echo text='hello world!' /> cool: <test:reverse>a <test:capitalize>test</test:capitalize> b</test:reverse> !")
|
97
|
+
assert_equal("hello world! cool: b TSET a !", r)
|
98
|
+
|
99
|
+
r = @t.parse("<test:reverse><test:echo text='hello world!' /></test:reverse>")
|
100
|
+
assert_equal("!dlrow olleh", r)
|
101
|
+
|
102
|
+
r = @t.parse("<test:reverse><test:capitalize>test</test:capitalize> <test:echo text='hello world!' /></test:reverse>")
|
103
|
+
assert_equal("!dlrow olleh TSET", r)
|
104
|
+
|
105
|
+
r = @t.parse("<test:reverse>12<test:capitalize>at</test:capitalize>34</test:reverse>")
|
106
|
+
assert_equal("43TA21", r)
|
107
|
+
end
|
108
|
+
def test_parse__loop
|
109
|
+
r = @t.parse(%{<test:count set="0" /><test:loop times="5"><test:count inc="true" /><test:count /></test:loop>})
|
110
|
+
assert_equal("12345", r)
|
111
|
+
|
112
|
+
r = @t.parse(%{Three Stooges: <test:each_item between=", ">"<test:item />"</test:each_item>})
|
113
|
+
assert_equal(%{Three Stooges: "Larry", "Moe", "Curly"}, r)
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_parse__fail_on_no_end_tag
|
117
|
+
assert_raises(Radius::MissingEndTagError) { @t.parse("<test:reverse>") }
|
118
|
+
end
|
119
|
+
def test_parse__fail_on_no_end_tag_2
|
120
|
+
assert_raises(Radius::MissingEndTagError) { @t.parse("<test:reverse><test:capitalize></test:reverse>") }
|
121
|
+
end
|
122
|
+
end
|
metadata
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.10
|
3
|
+
specification_version: 1
|
4
|
+
name: radius
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.0.1
|
7
|
+
date: 2006-01-21
|
8
|
+
summary: Powerful tag-based template system.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email:
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description: "Radius is a small, but powerful tag-based template language inspired by the
|
15
|
+
template languages used in MovableType and TextPattern."
|
16
|
+
autorequire: radius
|
17
|
+
default_executable:
|
18
|
+
bindir: bin
|
19
|
+
has_rdoc: true
|
20
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
21
|
+
requirements:
|
22
|
+
-
|
23
|
+
- ">"
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: 0.0.0
|
26
|
+
version:
|
27
|
+
platform: ruby
|
28
|
+
authors: []
|
29
|
+
files:
|
30
|
+
- DSL-SPEC
|
31
|
+
- lib
|
32
|
+
- QUICKSTART
|
33
|
+
- Rakefile
|
34
|
+
- README
|
35
|
+
- ROADMAP
|
36
|
+
- test
|
37
|
+
- lib/radius.rb
|
38
|
+
- test/radius_test.rb
|
39
|
+
test_files: []
|
40
|
+
rdoc_options:
|
41
|
+
- "--title"
|
42
|
+
- "Radius -- Powerful Tag-Based Templates"
|
43
|
+
- "--main"
|
44
|
+
- README
|
45
|
+
- "--line-numbers"
|
46
|
+
- ROADMAP
|
47
|
+
- QUICKSTART
|
48
|
+
- DSL-SPEC
|
49
|
+
- README
|
50
|
+
extra_rdoc_files: []
|
51
|
+
executables: []
|
52
|
+
extensions: []
|
53
|
+
requirements:
|
54
|
+
- none
|
55
|
+
dependencies: []
|