radius 0.0.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (9) hide show
  1. data/CHANGELOG +12 -0
  2. data/QUICKSTART +232 -45
  3. data/README +61 -15
  4. data/ROADMAP +4 -10
  5. data/Rakefile +50 -8
  6. data/lib/radius.rb +415 -75
  7. data/test/radius_test.rb +263 -113
  8. metadata +3 -4
  9. data/DSL-SPEC +0 -151
@@ -1,84 +1,54 @@
1
1
  require 'test/unit'
2
2
  require 'radius'
3
3
 
4
- class TestContext < Radius::Context
5
- def initialize
6
- @prefix = "test"
7
- @items = ["Larry", "Moe", "Curly"]
8
- end
9
-
10
- def echo(attr)
11
- attr["text"]
12
- end
13
-
14
- def add(attr)
15
- (attr["param1"].to_i + attr["param2"].to_i).to_s
16
- end
17
-
18
- def reverse(attr)
19
- yield.reverse
20
- end
4
+ module RadiusTestHelper
5
+ class TestContext < Radius::Context; end
21
6
 
22
- def capitalize(attr)
23
- yield.upcase
24
- end
25
-
26
- def count(attr)
27
- case
28
- when attr["set"]
29
- @count = attr["set"].to_i
30
- ""
31
- when attr["inc"] == "true"
32
- @count = (@count || 0) + 1
33
- ""
34
- else
35
- @count.to_s
7
+ def new_context
8
+ Radius::Context.new do |c|
9
+ c.define_tag("reverse" ) { |tag| tag.expand.reverse }
10
+ c.define_tag("capitalize") { |tag| tag.expand.upcase }
11
+ c.define_tag("attr") { |tag| tag.attr.inspect }
36
12
  end
37
13
  end
38
14
 
39
- def repeat(attr)
40
- string = ''
41
- (attr['count'] || '1').to_i.times { string << yield }
42
- string
43
- end
44
-
45
- def each_item(attr)
46
- result = []
47
- @items.each { |@item| result << yield }
48
- @item = nil
49
- result.join(attr["between"] || "")
50
- end
51
-
52
- def item(attr)
53
- @item
54
- end
55
-
56
- def hello(attr)
57
- "Hello #{attr['name'] || 'World'}!"
15
+ def define_tag(name, options = {}, &block)
16
+ @context.define_tag name, options, &block
58
17
  end
59
18
  end
60
19
 
61
20
  class RadiusContextTest < Test::Unit::TestCase
21
+ include RadiusTestHelper
22
+
62
23
  def setup
63
- @context = TestContext.new
24
+ @context = new_context
64
25
  end
65
26
 
66
27
  def test_initialize
67
28
  @context = Radius::Context.new
68
- assert_equal 'radius', @context.prefix
69
29
  end
70
30
 
71
- def test_render_tag__individual
72
- text = @context.render_tag('hello')
73
- assert_equal('Hello World!', text)
74
-
75
- text = @context.render_tag('hello', 'name' => 'John')
76
- assert_equal('Hello John!', text)
31
+ def test_initialize_with_block
32
+ @context = Radius::Context.new do |c|
33
+ assert_kind_of Radius::Context, c
34
+ c.define_tag('test') { 'just a test' }
35
+ end
36
+ assert_not_equal Hash.new, @context.definitions
37
+ end
38
+
39
+ def test_with
40
+ got = @context.with do |c|
41
+ assert_equal @context, c
42
+ end
43
+ assert_equal @context, got
77
44
  end
78
45
 
79
- def test_render_tag__container
80
- text = @context.render_tag('repeat', 'count' => '5') { 'o' }
81
- assert_equal('ooooo', text)
46
+ def test_render_tag
47
+ define_tag "hello" do |tag|
48
+ "Hello #{tag.attr['name'] || 'World'}!"
49
+ end
50
+ assert_render_tag_output 'Hello World!', 'hello'
51
+ assert_render_tag_output 'Hello John!', 'hello', 'name' => 'John'
82
52
  end
83
53
 
84
54
  def test_render_tag__undefined_tag
@@ -86,14 +56,6 @@ class RadiusContextTest < Test::Unit::TestCase
86
56
  assert_equal "undefined tag `undefined_tag'", e.message
87
57
  end
88
58
 
89
- def test_render_tag__undefined_tag_with_wrong_signature
90
- class << @context
91
- def helper_method
92
- end
93
- end
94
- assert_raises(Radius::UndefinedTagError) { @context.render_tag('helper_method') }
95
- end
96
-
97
59
  def test_tag_missing
98
60
  class << @context
99
61
  def tag_missing(tag, attr, &block)
@@ -102,68 +64,256 @@ class RadiusContextTest < Test::Unit::TestCase
102
64
  end
103
65
 
104
66
  text = ''
105
- assert_nothing_raised { text = @context.render_tag('undefined_tag', 'cool' => 'beans') }
106
-
107
67
  expected = %{undefined tag `undefined_tag' with attributes {"cool"=>"beans"}}
68
+ assert_nothing_raised { text = @context.render_tag('undefined_tag', 'cool' => 'beans') }
108
69
  assert_equal expected, text
109
70
  end
71
+
72
+ private
73
+
74
+ def assert_render_tag_output(output, *render_tag_params)
75
+ assert_equal output, @context.render_tag(*render_tag_params)
76
+ end
77
+
110
78
  end
111
79
 
112
80
  class RadiusParserTest < Test::Unit::TestCase
81
+ include RadiusTestHelper
82
+
113
83
  def setup
114
- @t = Radius::Parser.new(TestContext.new )
84
+ @context = new_context
85
+ @parser = Radius::Parser.new(@context, :tag_prefix => 'r')
115
86
  end
116
87
 
117
- def test_parse_individual
118
- r = @t.parse_individual(%{<<test:echo text="hello world!" />>})
119
- assert_equal("<hello world!>", r)
120
-
121
- r = @t.parse_individual(%{<test:add param1="1" param2='2'/>})
122
- assert_equal("3", r)
123
-
124
- r = @t.parse_individual(%{a <test:echo text="3 + 1 =" /> <test:add param1="3" param2="1"/> b})
125
- assert_equal("a 3 + 1 = 4 b", r)
88
+ def test_initialize
89
+ @parser = Radius::Parser.new
90
+ assert_kind_of Radius::Context, @parser.context
91
+ end
92
+
93
+ def test_initialize_with_params
94
+ @parser = Radius::Parser.new(TestContext.new)
95
+ assert_kind_of TestContext, @parser.context
96
+
97
+ @parser = Radius::Parser.new(:context => TestContext.new)
98
+ assert_kind_of TestContext, @parser.context
99
+
100
+ @parser = Radius::Parser.new('context' => TestContext.new)
101
+ assert_kind_of TestContext, @parser.context
102
+
103
+ @parser = Radius::Parser.new(:tag_prefix => 'r')
104
+ assert_kind_of Radius::Context, @parser.context
105
+ assert_equal 'r', @parser.tag_prefix
106
+
107
+ @parser = Radius::Parser.new(TestContext.new, :tag_prefix => 'r')
108
+ assert_kind_of TestContext, @parser.context
109
+ assert_equal 'r', @parser.tag_prefix
110
+ end
111
+
112
+ def test_parse_individual_tags_and_parameters
113
+ define_tag "add" do |tag|
114
+ tag.attr["param1"].to_i + tag.attr["param2"].to_i
115
+ end
116
+ assert_parse_output "<3>", %{<<r:add param1="1" param2='2'/>>}
126
117
  end
127
118
 
128
119
  def test_parse_attributes
129
- r = @t.parse_attributes(%{ a="1" b='2'c="3"d="'" })
130
- assert_equal({"a" => "1", "b" => "2", "c" => "3", "d" => "'"}, r)
120
+ attributes = %{{"a"=>"1", "b"=>"2", "c"=>"3", "d"=>"'"}}
121
+ assert_parse_output attributes, %{<r:attr a="1" b='2'c="3"d="'" />}
122
+ assert_parse_output attributes, %{<r:attr a="1" b='2'c="3"d="'"></r:attr>}
131
123
  end
132
124
 
133
- def test_parse
134
- r = @t.parse(%{<<test:echo text="hello world!" />>})
135
- assert_equal("<hello world!>", r)
136
-
137
- r = @t.parse("<test:reverse>test</test:reverse>")
138
- assert_equal("test".reverse, r)
139
-
140
- r = @t.parse("<test:reverse>test</test:reverse> <test:capitalize>test</test:capitalize>")
141
- assert_equal("tset TEST", r)
142
-
143
- r = @t.parse("<test:echo text='hello world!' /> cool: <test:reverse>a <test:capitalize>test</test:capitalize> b</test:reverse> !")
144
- assert_equal("hello world! cool: b TSET a !", r)
125
+ def test_parse_attributes_with_slashes_or_angle_brackets
126
+ slash = %{{"slash"=>"/"}}
127
+ angle = %{{"angle"=>">"}}
128
+ assert_parse_output slash, %{<r:attr slash="/"></r:attr>}
129
+ assert_parse_output slash, %{<r:attr slash="/"><r:attr /></r:attr>}
130
+ assert_parse_output angle, %{<r:attr angle=">"></r:attr>}
131
+ end
132
+
133
+ def test_things_that_should_be_left_alone
134
+ # The parser currently fails on these assertions
135
+ #assert_parsed_either_way_is_unchanged %{ test="2"="4" }
136
+ #assert_parsed_either_way_is_unchanged %{="2" }
137
+ end
145
138
 
146
- r = @t.parse("<test:reverse><test:echo text='hello world!' /></test:reverse>")
147
- assert_equal("!dlrow olleh", r)
148
-
149
- r = @t.parse("<test:reverse><test:capitalize>test</test:capitalize> <test:echo text='hello world!' /></test:reverse>")
150
- assert_equal("!dlrow olleh TSET", r)
151
-
152
- r = @t.parse("<test:reverse>12<test:capitalize>at</test:capitalize>34</test:reverse>")
153
- assert_equal("43TA21", r)
139
+ def test_parse_result_is_always_a_string
140
+ define_tag("twelve") { 12 }
141
+ assert_parse_output "12", "<r:twelve />"
154
142
  end
155
- def test_parse__looping
156
- r = @t.parse(%{<test:count set="0" /><test:repeat count="5"><test:count inc="true" /><test:count /></test:repeat>})
157
- assert_equal("12345", r)
158
-
159
- r = @t.parse(%{Three Stooges: <test:each_item between=", ">"<test:item />"</test:each_item>})
160
- assert_equal(%{Three Stooges: "Larry", "Moe", "Curly"}, r)
143
+
144
+ def test_parse_double_tags
145
+ assert_parse_output "test".reverse, "<r:reverse>test</r:reverse>"
146
+ assert_parse_output "tset TEST", "<r:reverse>test</r:reverse> <r:capitalize>test</r:capitalize>"
147
+ end
148
+
149
+ def test_parse_tag_nesting
150
+ define_tag("parent", :for => '')
151
+ define_tag("parent:child", :for => '')
152
+ define_tag("extra", :for => '')
153
+ define_tag("nesting") { |tag| tag.nesting }
154
+ define_tag("extra:nesting") { |tag| tag.nesting.gsub(':', ' > ') }
155
+ define_tag("parent:child:nesting") { |tag| tag.nesting.gsub(':', ' * ') }
156
+ assert_parse_output "nesting", "<r:nesting />"
157
+ assert_parse_output "parent:nesting", "<r:parent:nesting />"
158
+ assert_parse_output "extra > nesting", "<r:extra:nesting />"
159
+ assert_parse_output "parent * child * nesting", "<r:parent:child:nesting />"
160
+ assert_parse_output "parent > extra > nesting", "<r:parent:extra:nesting />"
161
+ assert_parse_output "parent > child > extra > nesting", "<r:parent:child:extra:nesting />"
162
+ assert_parse_output "parent * extra * child * nesting", "<r:parent:extra:child:nesting />"
163
+ assert_parse_output "parent > extra > child > extra > nesting", "<r:parent:extra:child:extra:nesting />"
164
+ assert_parse_output "parent > extra > child > extra > nesting", "<r:parent><r:extra><r:child><r:extra><r:nesting /></r:extra></r:child></r:extra></r:parent>"
165
+ assert_parse_output "extra * parent * child * nesting", "<r:extra:parent:child:nesting />"
166
+ assert_parse_output "extra > parent > nesting", "<r:extra><r:parent:nesting /></r:extra>"
167
+ assert_parse_output "extra * parent * child * nesting", "<r:extra:parent><r:child:nesting /></r:extra:parent>"
168
+ assert_raises(Radius::UndefinedTagError) { @parser.parse("<r:child />") }
169
+ end
170
+
171
+ def test_parse_tag_nesting_2
172
+ define_tag("parent", :for => '')
173
+ define_tag("parent:child", :for => '')
174
+ define_tag "content" do |tag|
175
+ tag.nesting
176
+ end
177
+ assert_parse_output 'parent:child:content', '<r:parent><r:child:content /></r:parent>'
178
+ end
179
+
180
+ def test_parse_tag__binding_do_missing
181
+ define_tag 'test' do |tag|
182
+ tag.missing!
183
+ end
184
+ e = assert_raises(Radius::UndefinedTagError) { @parser.parse("<r:test />") }
185
+ assert_equal "undefined tag `test'", e.message
186
+ end
187
+
188
+ def test_parse_tag__binding_render_tag
189
+ define_tag('test') { |tag| "Hello #{tag.attr['name']}!" }
190
+ define_tag('hello') { |tag| tag.render('test', tag.attr) }
191
+ assert_parse_output 'Hello John!', '<r:hello name="John" />'
192
+ end
193
+ def test_parse_tag__binding_render_tag_with_block
194
+ define_tag('test') { |tag| "Hello #{tag.expand}!" }
195
+ define_tag('hello') { |tag| tag.render('test') { tag.expand } }
196
+ assert_parse_output 'Hello John!', '<r:hello>John</r:hello>'
197
+ end
198
+
199
+ def test_tag_locals
200
+ define_tag "outer" do |tag|
201
+ tag.locals.var = 'outer'
202
+ tag.expand
203
+ end
204
+ define_tag "outer:inner" do |tag|
205
+ tag.locals.var = 'inner'
206
+ tag.expand
207
+ end
208
+ define_tag "outer:var" do |tag|
209
+ tag.locals.var
210
+ end
211
+ assert_parse_output 'outer', "<r:outer><r:var /></r:outer>"
212
+ assert_parse_output 'outer:inner:outer', "<r:outer><r:var />:<r:inner><r:var /></r:inner>:<r:var /></r:outer>"
213
+ assert_parse_output 'outer:inner:outer:inner:outer', "<r:outer><r:var />:<r:inner><r:var />:<r:outer><r:var /></r:outer>:<r:var /></r:inner>:<r:var /></r:outer>"
214
+ assert_parse_output 'outer', "<r:outer:var />"
215
+ end
216
+
217
+ def test_tag_globals
218
+ define_tag "set" do |tag|
219
+ tag.globals.var = tag.attr['value']
220
+ ''
221
+ end
222
+ define_tag "var" do |tag|
223
+ tag.globals.var
224
+ end
225
+ assert_parse_output " true false", %{<r:var /> <r:set value="true" /> <r:var /> <r:set value="false" /> <r:var />}
161
226
  end
162
227
 
163
- def test_parse__fail_on_no_end_tag
164
- assert_raises(Radius::MissingEndTagError) { @t.parse("<test:reverse>") }
228
+ def test_parse_loops
229
+ @item = nil
230
+ define_tag "each" do |tag|
231
+ result = []
232
+ ["Larry", "Moe", "Curly"].each do |item|
233
+ tag.locals.item = item
234
+ result << tag.expand
235
+ end
236
+ result.join(tag.attr["between"] || "")
237
+ end
238
+ define_tag "each:item" do |tag|
239
+ tag.locals.item
240
+ end
241
+ assert_parse_output %{Three Stooges: "Larry", "Moe", "Curly"}, %{Three Stooges: <r:each between=", ">"<r:item />"</r:each>}
165
242
  end
166
- def test_parse__fail_on_no_end_tag_2
167
- assert_raises(Radius::MissingEndTagError) { @t.parse("<test:reverse><test:capitalize></test:reverse>") }
243
+
244
+ def test_tag_option_for
245
+ define_tag 'fun', :for => 'just for kicks'
246
+ assert_parse_output 'just for kicks', '<r:fun />'
168
247
  end
248
+
249
+ def test_tag_expose_option
250
+ define_tag 'user', :for => users.first, :expose => ['name', :age]
251
+ assert_parse_output 'John', '<r:user:name />'
252
+ assert_parse_output '25', '<r:user><r:age /></r:user>'
253
+ e = assert_raises(Radius::UndefinedTagError) { @parser.parse "<r:user:email />" }
254
+ assert_equal "undefined tag `email'", e.message
255
+ end
256
+
257
+ def test_tag_expose_attributes_option_on_by_default
258
+ define_tag 'user', :for => user_with_attributes
259
+ assert_parse_output 'John', '<r:user:name />'
260
+ end
261
+ def test_tag_expose_attributes_set_to_false
262
+ define_tag 'user_without_attributes', :for => user_with_attributes, :attributes => false
263
+ assert_raises(Radius::UndefinedTagError) { @parser.parse "<r:user_without_attributes:name />" }
264
+ end
265
+
266
+ def test_tag_options_must_contain_a_for_option_if_methods_are_exposed
267
+ e = assert_raises(ArgumentError) { define_tag('fun', :expose => :today) { 'test' } }
268
+ assert_equal "tag definition must contain a :for option when used with the :expose option", e.message
269
+ end
270
+
271
+ def test_parse_fail_on_missing_end_tag
272
+ assert_raises(Radius::MissingEndTagError) { @parser.parse("<r:reverse>") }
273
+ assert_raises(Radius::MissingEndTagError) { @parser.parse("<r:reverse><r:capitalize></r:reverse>") }
274
+ end
275
+
276
+ protected
277
+
278
+ def assert_parse_output(output, input, message = nil)
279
+ r = @parser.parse(input)
280
+ assert_equal(output, r, message)
281
+ end
282
+
283
+ def assert_parsed_is_unchanged(something)
284
+ assert_parse_output something, something
285
+ end
286
+
287
+ def assert_parsed_either_way_is_unchanged(middle)
288
+ assert_parsed_is_unchanged %{<r:attr#{middle}/>}
289
+ assert_parsed_is_unchanged %{<r:attr#{middle}></r:attr>}
290
+ end
291
+
292
+ class User
293
+ attr_accessor :name, :age, :email, :friend
294
+ def initialize(name, age, email)
295
+ @name, @age, @email = name, age, email
296
+ end
297
+ def <=>(other)
298
+ name <=> other.name
299
+ end
300
+ end
301
+
302
+ class UserWithAttributes < User
303
+ def attributes
304
+ { :name => name, :age => age, :email => email }
305
+ end
306
+ end
307
+
308
+ def users
309
+ [
310
+ User.new('John', 25, 'test@johnwlong.com'),
311
+ User.new('James', 27, 'test@jameslong.com')
312
+ ]
313
+ end
314
+
315
+ def user_with_attributes
316
+ UserWithAttributes.new('John', 25, 'test@johnwlong.com')
317
+ end
318
+
169
319
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.10
3
3
  specification_version: 1
4
4
  name: radius
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.0.2
7
- date: 2006-02-14
6
+ version: 0.5.0
7
+ date: 2006-05-01
8
8
  summary: Powerful tag-based template system.
9
9
  require_paths:
10
10
  - lib
@@ -29,8 +29,8 @@ platform: ruby
29
29
  authors: []
30
30
  files:
31
31
  - CHANGELOG
32
- - DSL-SPEC
33
32
  - lib
33
+ - pkg
34
34
  - QUICKSTART
35
35
  - Rakefile
36
36
  - README
@@ -49,7 +49,6 @@ extra_rdoc_files:
49
49
  - README
50
50
  - QUICKSTART
51
51
  - ROADMAP
52
- - DSL-SPEC
53
52
  - CHANGELOG
54
53
  executables: []
55
54
  extensions: []