radius 0.5.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +4 -0
- data/Rakefile +1 -3
- data/lib/radius.rb +4 -4
- data/pkg/radius-0.5.0.gem +0 -0
- data/pkg/radius-0.5.0.tgz +0 -0
- data/pkg/radius-0.5.0.zip +0 -0
- data/pkg/radius-0.5.0/CHANGELOG +25 -0
- data/pkg/radius-0.5.0/QUICKSTART +323 -0
- data/pkg/radius-0.5.0/README +97 -0
- data/pkg/radius-0.5.0/ROADMAP +12 -0
- data/pkg/radius-0.5.0/Rakefile +86 -0
- data/pkg/radius-0.5.0/lib/radius.rb +497 -0
- data/pkg/radius-0.5.0/test/radius_test.rb +321 -0
- data/test/radius_test.rb +15 -13
- metadata +50 -32
data/CHANGELOG
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
= Change Log
|
2
2
|
|
3
|
+
=== 0.5.1
|
4
|
+
* Fixed a problem with parsing quotes where a single tag preceding a double tag would consume the start
|
5
|
+
tag of the double tag if both contained attributes.
|
6
|
+
|
3
7
|
=== 0.5.0
|
4
8
|
* Created a DSL for tag definitions (introducing a DSL makes this version of Radiant incompatible with
|
5
9
|
the last). The DSL has the following features:
|
data/Rakefile
CHANGED
@@ -4,7 +4,7 @@ require 'rake/rdoctask'
|
|
4
4
|
require 'rake/gempackagetask'
|
5
5
|
|
6
6
|
PKG_NAME = 'radius'
|
7
|
-
PKG_VERSION = '0.5.
|
7
|
+
PKG_VERSION = '0.5.1'
|
8
8
|
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
9
9
|
RUBY_FORGE_PROJECT = PKG_NAME
|
10
10
|
RUBY_FORGE_USER = 'jlong'
|
@@ -83,6 +83,4 @@ task :release => [:gem, :package] do
|
|
83
83
|
files.each do |file|
|
84
84
|
system("rubyforge add_release #{RUBY_FORGE_GROUPID} #{RUBY_FORGE_PACKAGEID} \"#{RELEASE_NAME}\" #{file}")
|
85
85
|
end
|
86
|
-
|
87
|
-
puts ">>>> done <<<<"
|
88
86
|
end
|
data/lib/radius.rb
CHANGED
@@ -406,10 +406,10 @@ module Radius
|
|
406
406
|
|
407
407
|
protected
|
408
408
|
|
409
|
-
def pre_parse(text)
|
410
|
-
re = %r{<#{@tag_prefix}:([\w:]+?)(\s+(?:\w+\s*=\s*(["'])
|
409
|
+
def pre_parse(text) # :nodoc:
|
410
|
+
re = %r{<#{@tag_prefix}:([\w:]+?)(\s+(?:\w+\s*=\s*(?:"[^"]*?"|'[^']*?')\s*)*|)>|</#{@tag_prefix}:([\w:]+?)\s*>}
|
411
411
|
if md = re.match(text)
|
412
|
-
start_tag, attr, end_tag = $1, $2, $
|
412
|
+
start_tag, attr, end_tag = $1, $2, $3
|
413
413
|
@stack.last.contents << ParseTag.new { parse_individual(md.pre_match) }
|
414
414
|
remaining = md.post_match
|
415
415
|
if start_tag
|
@@ -444,7 +444,7 @@ module Radius
|
|
444
444
|
end
|
445
445
|
|
446
446
|
def parse_individual(text) # :nodoc:
|
447
|
-
re = %r{<#{@tag_prefix}:([\w:]+?)(\s+(?:\w+\s*=\s*(["'])
|
447
|
+
re = %r{<#{@tag_prefix}:([\w:]+?)(\s+(?:\w+\s*=\s*(?:"[^"]*?"|'[^']*?')\s*)*|)/>}
|
448
448
|
if md = re.match(text)
|
449
449
|
attr = parse_attributes($2)
|
450
450
|
replace = @context.render_tag($1, attr)
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,25 @@
|
|
1
|
+
= Change Log
|
2
|
+
|
3
|
+
=== 0.5.1
|
4
|
+
* Fixed a problem with parsing quotes where a single tag preceding a double tag would consume the start
|
5
|
+
tag of the double tag if both contained attributes.
|
6
|
+
|
7
|
+
=== 0.5.0
|
8
|
+
* Created a DSL for tag definitions (introducing a DSL makes this version of Radiant incompatible with
|
9
|
+
the last). The DSL has the following features:
|
10
|
+
- full support for nested tags
|
11
|
+
- global and local tag variables
|
12
|
+
- Contexts can now be defined dynamically (instead of being subclassed)
|
13
|
+
- see the QUICKSTART for more info
|
14
|
+
* Many refactorings of the library and unit tests.
|
15
|
+
* Changed the license to the MIT-LICENSE.
|
16
|
+
* Updated documentation to reflect the changes.
|
17
|
+
* Updated the version number to reflect the maturity of the code base.
|
18
|
+
|
19
|
+
=== 0.0.2
|
20
|
+
* Refactored Parser to use Context#render_tag instead of #send when rendering tags defined on a Context.
|
21
|
+
* UndefinedTagError is now thrown when Parser tries to render a tag which doesn't exist on a Context.
|
22
|
+
* Added Context#tag_missing which works like method_method missing on Object, but is tag specific.
|
23
|
+
|
24
|
+
=== 0.0.1
|
25
|
+
* First release.
|
@@ -0,0 +1,323 @@
|
|
1
|
+
= Radius Quick Start
|
2
|
+
|
3
|
+
|
4
|
+
== Defining Tags
|
5
|
+
|
6
|
+
Before you can parse a template with Radius you need to create a Context object which defines
|
7
|
+
the tags that will be used in the template. This is actually quite simple:
|
8
|
+
|
9
|
+
require 'radius'
|
10
|
+
|
11
|
+
context = Context.new
|
12
|
+
context.define_tag "hello" do |tag|
|
13
|
+
"Hello #{tag.attr['name'] || 'World'}!"
|
14
|
+
end
|
15
|
+
|
16
|
+
Once you have defined a context you can easily create a Parser:
|
17
|
+
|
18
|
+
parser = Radius::Parser.new(context)
|
19
|
+
puts parser.parse('<p><radius:hello /></p>')
|
20
|
+
puts parser.parse('<p><radius:hello name="John" /></p>')
|
21
|
+
|
22
|
+
This code will output:
|
23
|
+
|
24
|
+
<p>Hello World!</p>
|
25
|
+
<p>Hello John!</p>
|
26
|
+
|
27
|
+
Note how you can pass attributes from the template to the context using the attributes hash.
|
28
|
+
Above, the first tag that was parsed didn't have a name attribute so the code in the +hello+
|
29
|
+
tag definition uses "World" instead. The second time the tag is parsed the name attribute is
|
30
|
+
set to "John" which is used to create the string "Hello John!". Tags that do not follow this
|
31
|
+
rule will be treated as if they were undefined (like normal methods).
|
32
|
+
|
33
|
+
|
34
|
+
== Container Tags
|
35
|
+
|
36
|
+
Radius also allows you to define "container" tags. That is, tags that contain content and
|
37
|
+
that may optionally manipulate it in some way. For example, if you have RedCloth installed
|
38
|
+
you could define another tag to parse and create Textile output:
|
39
|
+
|
40
|
+
require 'redcloth'
|
41
|
+
|
42
|
+
context.define_tag "textile" do |tag|
|
43
|
+
contents = tag.expand
|
44
|
+
RedCloth.new(contents).to_html
|
45
|
+
end
|
46
|
+
|
47
|
+
(The code <tt>tag.expand</tt> above returns the contents of the template between the start and end
|
48
|
+
tags.)
|
49
|
+
|
50
|
+
With the code above your parser can easily handle Textile:
|
51
|
+
|
52
|
+
parser.parse('<radius:textile>h1. Hello **World**!</radius:textile>')
|
53
|
+
|
54
|
+
This code will output:
|
55
|
+
|
56
|
+
<h1>Hello <strong>World</strong>!</h1>
|
57
|
+
|
58
|
+
|
59
|
+
== Nested Tags
|
60
|
+
|
61
|
+
But wait!--it gets better. Because container tags can manipulate the content they contain
|
62
|
+
you can use them to iterate over collections:
|
63
|
+
|
64
|
+
context = Context.new
|
65
|
+
|
66
|
+
context.define_tag "stooge" do |tag|
|
67
|
+
content = ''
|
68
|
+
["Larry", "Moe", "Curly"].each do |name|
|
69
|
+
tag.locals.name = name
|
70
|
+
content << tag.expand
|
71
|
+
end
|
72
|
+
content
|
73
|
+
end
|
74
|
+
|
75
|
+
context.define_tag "stooge:name" do
|
76
|
+
tag.locals.name
|
77
|
+
end
|
78
|
+
|
79
|
+
parser = Radius::Parser.new(context)
|
80
|
+
|
81
|
+
template = <<-TEMPLATE
|
82
|
+
<ul>
|
83
|
+
<radius:stooge>
|
84
|
+
<li><radius:name /></li>
|
85
|
+
</radius:stooge>
|
86
|
+
</ul>
|
87
|
+
TEMPLATE
|
88
|
+
|
89
|
+
puts parser.parse(template)
|
90
|
+
|
91
|
+
This code will output:
|
92
|
+
|
93
|
+
<ul>
|
94
|
+
|
95
|
+
<li>Larry</li>
|
96
|
+
|
97
|
+
<li>Moe</li>
|
98
|
+
|
99
|
+
<li>Curly</li>
|
100
|
+
|
101
|
+
</ul>
|
102
|
+
|
103
|
+
Note how the definition for the +name+ tag is defined. Because "name" is prefixed
|
104
|
+
with "stooge:" the +name+ tag cannot appear outside the +stooge+ tag. Had it been defined
|
105
|
+
simply as "name" it would be valid anywhere, even outside the +stooge+ tag (which was
|
106
|
+
not what we wanted). Using the colon operator you can define tags with any amount of
|
107
|
+
nesting.
|
108
|
+
|
109
|
+
|
110
|
+
== Exposing Objects to Templates
|
111
|
+
|
112
|
+
During normal operation, you will often want to expose certain objects to your templates.
|
113
|
+
Writing the tags to do this all by hand would be cumbersome of Radius did not provide
|
114
|
+
several mechanisms to make this easier. The first is a way of exposing objects as tags
|
115
|
+
on the context object. To expose an object simply call the +define_tag+
|
116
|
+
method with the +for+ option:
|
117
|
+
|
118
|
+
context.define_tag "count", :for => 1
|
119
|
+
|
120
|
+
This would expose the object <tt>1</tt> to the template as the +count+ tag. It's basically the
|
121
|
+
equivalent of writing:
|
122
|
+
|
123
|
+
context.define_tag("count") { 1 }
|
124
|
+
|
125
|
+
So far this doesn't save you a whole lot of typing, but suppose you want to expose certain
|
126
|
+
methods that are on that object? You could do this:
|
127
|
+
|
128
|
+
context.define_tag "user", :for => user, :expose => [ :name, :age, :email ]
|
129
|
+
|
130
|
+
This will add a total of four tags to the context. One for the <tt>user</tt> variable, and
|
131
|
+
one for each of the three methods listed in the +expose+ clause. You could now get the user's
|
132
|
+
name inside your template like this:
|
133
|
+
|
134
|
+
<radius:user><radius:name /></radius:user>
|
135
|
+
|
136
|
+
If "John" was the value stored in <tt>user.name</tt> the template would render as "John".
|
137
|
+
|
138
|
+
|
139
|
+
== Tag Shorthand
|
140
|
+
|
141
|
+
In the example above we made reference to <tt>user.name</tt> in our template by using the
|
142
|
+
following code:
|
143
|
+
|
144
|
+
<radius:user><radius:name /></radius:user>
|
145
|
+
|
146
|
+
There is a much easer way to refer to the <tt>user.name</tt> variable. Use the colon operator
|
147
|
+
to "scope" the reference to <tt>name</tt>:
|
148
|
+
|
149
|
+
<radius:user:name />
|
150
|
+
|
151
|
+
Radius allows you to use this shortcut for all tags.
|
152
|
+
|
153
|
+
|
154
|
+
== Changing the Tag Prefix
|
155
|
+
|
156
|
+
By default, all Radius tags must begin with "radius". You can change this by altering the
|
157
|
+
tag_prefix attribute on a Parser. For example:
|
158
|
+
|
159
|
+
parser = Radius::Parser.new(context, :tag_prefix => 'r')
|
160
|
+
|
161
|
+
Now, when parsing templates with +parser+, Radius will require that every tag begin with "r"
|
162
|
+
instead of "radius".
|
163
|
+
|
164
|
+
|
165
|
+
== Custom Behavior for Undefined Tags
|
166
|
+
|
167
|
+
Context#tag_missing behaves much like Object#method_missing only it allows you to define
|
168
|
+
specific behavior for when a tag is not defined on a Context. For example:
|
169
|
+
|
170
|
+
class LazyContext < Radius::Context
|
171
|
+
def tag_missing(tag, attr, &block)
|
172
|
+
"<strong>ERROR: Undefined tag `#{tag}' with attributes #{attr.inspect}</strong>"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
parser = Radius::Parser.new(LazyContext.new, :tag_prefix => 'lazy')
|
177
|
+
puts parser.parse('<lazy:weird value="true" />')
|
178
|
+
|
179
|
+
This will output:
|
180
|
+
|
181
|
+
<strong>ERROR: Undefined tag `weird' with attributes {"value"=>"true"}</strong>
|
182
|
+
|
183
|
+
Normally, when the Radius Parser encounters an undefined tag for a Context it raises an
|
184
|
+
UndefinedTagError, but since we have defined #tag_missing on LazyContext the Parser now
|
185
|
+
outputs a nicely formated error message when we parse a string that does not contain a
|
186
|
+
valid tag.
|
187
|
+
|
188
|
+
|
189
|
+
== Tag Bindings
|
190
|
+
|
191
|
+
Radius passes a TagBinding into the block of the Context#define_tag method. The tag
|
192
|
+
binding is useful for a number of tasks. A tag binding has an #expand instance method
|
193
|
+
which processes a tag's contents and returns the result. It also has a #attr method
|
194
|
+
which returns a hash of the attributes that were passed into the tag. TagBinding also
|
195
|
+
contains the TagBinding#single? and TagBinding#double? methods which return true or false
|
196
|
+
based on wether the tag is a container tag or not. More about the methods which are
|
197
|
+
available on tag bindings can be found on the Radius::TagBinding documentation page.
|
198
|
+
|
199
|
+
|
200
|
+
== Tag Binding Locals, Globals, and Context Sensitive Tags
|
201
|
+
|
202
|
+
A TagBinding also contains two OpenStruct-like objects which are useful when developing
|
203
|
+
tags. TagBinding#globals is useful for storing variables which you would like to be
|
204
|
+
accessible to all tags:
|
205
|
+
|
206
|
+
context.define_tag "inc" do |tag|
|
207
|
+
tag.globals.count ||= 0
|
208
|
+
tag.globals.count += 1
|
209
|
+
end
|
210
|
+
|
211
|
+
context.define_tag "count" do |tag|
|
212
|
+
tag.globals.count || 0
|
213
|
+
end
|
214
|
+
|
215
|
+
TagBinding#locals mirrors the variables that are in TagBinding#globals, but allows child
|
216
|
+
tags to redefine variables. This is valuable when defining context sensitive tags:
|
217
|
+
|
218
|
+
require 'radius'
|
219
|
+
|
220
|
+
class Person
|
221
|
+
attr_accessor :name, :friend
|
222
|
+
def initialize(name)
|
223
|
+
@name = name
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
jack = Person.new('Jack')
|
228
|
+
jill = Person.new('Jill')
|
229
|
+
jack.friend = jill
|
230
|
+
jill.friend = jack
|
231
|
+
|
232
|
+
context = Radius::Context.new do |c|
|
233
|
+
c.define_tag "jack" do |tag|
|
234
|
+
tag.locals.person = jack
|
235
|
+
tag.expand
|
236
|
+
end
|
237
|
+
c.define_tag "jill" do |tag|
|
238
|
+
tag.locals.person = jill
|
239
|
+
tag.expand
|
240
|
+
end
|
241
|
+
c.define_tag "name" do |tag|
|
242
|
+
tag.locals.person.name rescue tag.missing!
|
243
|
+
end
|
244
|
+
c.define_tag "friend" do |tag|
|
245
|
+
tag.locals.person = tag.locals.person.friend rescue tag.missing!
|
246
|
+
tag.expand
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
parser = Radius::Parser.new(context, :tag_prefix => 'r')
|
251
|
+
|
252
|
+
parser.parse('<r:jack:name />') #=> "Jack"
|
253
|
+
parser.parse('<r:jill:name />') #=> "Jill"
|
254
|
+
parser.parse('<r:jill:friend:name />') #=> "Jack"
|
255
|
+
parser.parse('<r:jill:friend:friend:name />') #=> "Jack"
|
256
|
+
parser.parse('<r:jill><r:friend:name /> and <r:name /></r:jill>') #=> "Jack and Jill"
|
257
|
+
parser.parse('<r:name />') # raises an UndefinedTagError exception
|
258
|
+
|
259
|
+
Notice how TagBinding#locals enables intelligent nesting. "<r:jill:name />" evaluates to
|
260
|
+
"Jill", but "<r:jill:friend:name />" evaluates to "Jack". Locals loose scope as soon as
|
261
|
+
the tag they were defined in closes. Globals on the other hand, never loose scope.
|
262
|
+
|
263
|
+
The final line in the example above demonstrates that calling "<r:name />" raises a
|
264
|
+
TagMissing error. This is because of the way the name tag was defined:
|
265
|
+
|
266
|
+
tag.locals.person.name rescue tag.missing!
|
267
|
+
|
268
|
+
If person is not defined on locals it will return nil. Calling #name on nil would normally
|
269
|
+
raise a NoMethodError exception, but because of the 'rescue' clause the TagBinding#missing!
|
270
|
+
method is called which fires off Context#tag_missing. By default Context#tag_missing raises
|
271
|
+
a UndefinedTagError exception. The 'rescue tag.missing!' idiom is extremly useful for adding
|
272
|
+
simple error checking to context sensitive tags.
|
273
|
+
|
274
|
+
|
275
|
+
== Tag Specificity
|
276
|
+
|
277
|
+
When Radius is presented with two tags that have the same name, but different nesting
|
278
|
+
Radius uses an algorithm similar to the way winning rules are calculated in Cascading Style
|
279
|
+
Sheets (CSS) to determine which definition should be used. Each time a tag is encountered
|
280
|
+
in a template potential tags are assigned specificity values and the tag with the highest
|
281
|
+
specificity wins.
|
282
|
+
|
283
|
+
For example, given the following tag definitions:
|
284
|
+
|
285
|
+
nesting
|
286
|
+
extra:nesting
|
287
|
+
parent:child:nesting
|
288
|
+
|
289
|
+
And template:
|
290
|
+
|
291
|
+
<r:parent:extra:child:nesting />
|
292
|
+
|
293
|
+
Radius will calculate specificity values like this:
|
294
|
+
|
295
|
+
nesting => 1.0.0.0
|
296
|
+
extra:nesting => 1.0.1.0
|
297
|
+
parent:child:nesting => 1.1.0.1
|
298
|
+
|
299
|
+
Meaning that parent:child:nesting will win. If a template contained:
|
300
|
+
|
301
|
+
<r:parent:child:extra:nesting />
|
302
|
+
|
303
|
+
The following specificity values would be assigned to each of the tag definitions:
|
304
|
+
|
305
|
+
nesting => 1.0.0.0
|
306
|
+
extra:nesting => 1.1.0.0
|
307
|
+
parent:child:nesting => 1.0.1.1
|
308
|
+
|
309
|
+
Meaning that extra:nesting would win because it is more "specific".
|
310
|
+
|
311
|
+
Values are assigned by assigning points to each of the tags from right to left.
|
312
|
+
Given a tag found in a template with nesting four levels deep, the maximum
|
313
|
+
specificity a tag could be assigned would be:
|
314
|
+
|
315
|
+
1.1.1.1
|
316
|
+
|
317
|
+
One point for each of the levels.
|
318
|
+
|
319
|
+
A deep understanding of tag specificity is not necessary to be effective with
|
320
|
+
Radius. For the most part you will find that Radius resolves tags precisely the
|
321
|
+
way that you would expect. If you find this section confusing forget about it and
|
322
|
+
refer back to it if you find that tags are resolving differently from the way that
|
323
|
+
you expected.
|
@@ -0,0 +1,97 @@
|
|
1
|
+
= Radius -- Powerful Tag-Based Templates
|
2
|
+
|
3
|
+
Radius is a powerful tag-based 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 XML, but can be used to generate any form of plain text (HTML, e-mail,
|
6
|
+
etc...).
|
7
|
+
|
8
|
+
== Example
|
9
|
+
|
10
|
+
With Radius, it is extremely easy to create custom tags and parse them. Here's a small
|
11
|
+
example:
|
12
|
+
|
13
|
+
require 'radius'
|
14
|
+
|
15
|
+
# Define tags on a context that will be available to a template:
|
16
|
+
context = Radius::Context.new do |c|
|
17
|
+
c.define_tag 'hello' do
|
18
|
+
'Hello world'
|
19
|
+
end
|
20
|
+
c.define_tag 'repeat' do |tag|
|
21
|
+
number = (tag.attr['times'] || '1').to_i
|
22
|
+
result = ''
|
23
|
+
number.times { result << tag.expand }
|
24
|
+
result
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Create a parser to parse tags that begin with 'r:'
|
29
|
+
parser = Radius::Parser.new(context, :tag_prefix => 'r')
|
30
|
+
|
31
|
+
# Parse tags and output the result
|
32
|
+
puts parser.parse(%{A small example:\n<r:repeat times="3">* <r:hello />!\n</r:repeat>})
|
33
|
+
|
34
|
+
Output:
|
35
|
+
|
36
|
+
A small example:
|
37
|
+
* Hello world!
|
38
|
+
* Hello world!
|
39
|
+
* Hello world!
|
40
|
+
|
41
|
+
|
42
|
+
= Quick Start
|
43
|
+
|
44
|
+
Read the QUICKSTART[link:files/QUICKSTART.html] to get up and running fast with Radius.
|
45
|
+
|
46
|
+
|
47
|
+
== Download
|
48
|
+
|
49
|
+
The latest version of Radius can be found on RubyForge:
|
50
|
+
|
51
|
+
http://rubyforge.org/projects/radius/
|
52
|
+
|
53
|
+
|
54
|
+
== Installation
|
55
|
+
|
56
|
+
It is recommended that you install Radius using the RubyGems packaging system:
|
57
|
+
|
58
|
+
% gem install --remote radius
|
59
|
+
|
60
|
+
You can also install Radius by copying lib/radius.rb into the Ruby load path.
|
61
|
+
|
62
|
+
|
63
|
+
== License
|
64
|
+
|
65
|
+
Radius is free software and may be redistributed under the terms of the MIT-LICENSE:
|
66
|
+
|
67
|
+
Copyright (c) 2006, John W. Long
|
68
|
+
|
69
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
70
|
+
software and associated documentation files (the "Software"), to deal in the Software
|
71
|
+
without restriction, including without limitation the rights to use, copy, modify, merge,
|
72
|
+
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
73
|
+
to whom the Software is furnished to do so, subject to the following conditions:
|
74
|
+
|
75
|
+
The above copyright notice and this permission notice shall be included in all copies or
|
76
|
+
substantial portions of the Software.
|
77
|
+
|
78
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
79
|
+
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
80
|
+
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
81
|
+
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
82
|
+
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
83
|
+
DEALINGS IN THE SOFTWARE.
|
84
|
+
|
85
|
+
|
86
|
+
== The Future
|
87
|
+
|
88
|
+
Radius is nearing completion, but is still very much in the development stages. Take a look
|
89
|
+
at the ROADMAP[link:files/ROADMAP.html] to see where we want to go.
|
90
|
+
|
91
|
+
If you are interested in helping with the development of Radiant, contact me and we'll talk.
|
92
|
+
|
93
|
+
Enjoy!
|
94
|
+
|
95
|
+
--
|
96
|
+
John Long ::
|
97
|
+
http://wiseheartdesign.com
|