radius 0.6.1 → 0.7.0.prerelease

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/CHANGELOG +21 -12
  2. data/LICENSE +19 -0
  3. data/QUICKSTART.rdoc +7 -7
  4. data/README.rdoc +10 -28
  5. data/Rakefile +8 -31
  6. data/VERSION +1 -0
  7. data/lib/radius.rb +3 -2
  8. data/lib/radius/context.rb +21 -13
  9. data/lib/radius/delegating_open_struct.rb +6 -0
  10. data/lib/radius/ord_string.rb +13 -0
  11. data/lib/radius/parse_tag.rb +1 -1
  12. data/lib/radius/parser.rb +25 -11
  13. data/lib/radius/parser/JavaScanner$Flavor.class +0 -0
  14. data/lib/radius/parser/JavaScanner$Tag.class +0 -0
  15. data/lib/radius/parser/JavaScanner.class +0 -0
  16. data/lib/radius/parser/JavaScanner.java +634 -0
  17. data/lib/radius/parser/JavaScanner.rl +179 -0
  18. data/lib/radius/parser/java_scanner.jar +0 -0
  19. data/lib/radius/parser/scanner.rb +1255 -0
  20. data/lib/radius/parser/{scan.rl → scanner.rl} +6 -4
  21. data/lib/radius/parser/squiggle_scanner.rb +1238 -0
  22. data/lib/radius/parser/squiggle_scanner.rl +126 -0
  23. data/lib/radius/utility.rb +10 -0
  24. data/lib/radius/version.rb +6 -12
  25. data/tasks/jeweler.rake +22 -0
  26. data/tasks/rdoc.rake +13 -0
  27. data/tasks/rubinius.rake +4 -0
  28. data/tasks/scan.rake +64 -12
  29. data/tasks/test.rake +7 -0
  30. data/test/benchmarks.rb +35 -0
  31. data/test/context_test.rb +2 -2
  32. data/test/multithreaded_test.rb +63 -0
  33. data/test/ord_string_test.rb +18 -0
  34. data/test/parser_test.rb +21 -4
  35. data/test/quickstart_test.rb +9 -11
  36. data/test/squiggle_test.rb +281 -0
  37. data/test/test_helper.rb +10 -2
  38. data/test/utility_test.rb +30 -0
  39. metadata +67 -64
  40. data.tar.gz.sig +0 -0
  41. data/Manifest.txt +0 -21
  42. data/lib/radius/parser/scan.rb +0 -700
  43. metadata.gz.sig +0 -0
@@ -0,0 +1,126 @@
1
+ %%{
2
+ machine parser;
3
+
4
+
5
+ # action _prefix { mark_pfx = p }
6
+ # action prefix {
7
+ # if data[mark_pfx..p-1] != @prefix
8
+ # @nodes.last << data[mark_pfx-1..p]
9
+ # fbreak;
10
+ # end
11
+ # }
12
+ action _starttag { mark_stg = p }
13
+ action starttag { @starttag = data[mark_stg..p-1] }
14
+ action _attr { mark_attr = p }
15
+ action attr {
16
+ @attrs[@nat] = @vat
17
+ }
18
+
19
+ action prematch {
20
+ @prematch_end = p
21
+ @prematch = data[0..p] if p > 0
22
+ }
23
+
24
+ action _nameattr { mark_nat = p }
25
+ action nameattr { @nat = data[mark_nat..p-1] }
26
+ action _valattr { mark_vat = p }
27
+ action valattr { @vat = data[mark_vat..p-1] }
28
+
29
+ action opentag { @flavor = :open }
30
+ action selftag { @flavor = :self }
31
+ action closetag { @flavor = :close }
32
+
33
+ action stopparse {
34
+ @cursor = p;
35
+ fbreak;
36
+ }
37
+
38
+
39
+ Closeout := empty;
40
+
41
+ # words
42
+ # PrefixChar = [\-A-Za-z0-9._?] ;
43
+ NameChar = [\-A-Za-z0-9._:?] ;
44
+ TagName = NameChar+ >_starttag %starttag;
45
+ # Prefix = PrefixChar+ >_prefix %prefix;
46
+
47
+ # Name = Prefix ":" TagName;
48
+
49
+ NameAttr = NameChar+ >_nameattr %nameattr;
50
+ Q1Char = ( "\\\'" | [^'] ) ;
51
+ Q1Attr = Q1Char* >_valattr %valattr;
52
+ Q2Char = ( "\\\"" | [^"] ) ;
53
+ Q2Attr = Q2Char* >_valattr %valattr;
54
+
55
+ Attr = NameAttr space* "=" space* ('"' Q2Attr '"' | "'" Q1Attr "'") space* >_attr %attr;
56
+ Attrs = (space+ Attr* | empty);
57
+
58
+ CloseTrailer = "/}" %selftag;
59
+ OpenTrailer = "}" %opentag;
60
+
61
+ Trailer = (OpenTrailer | CloseTrailer);
62
+
63
+ # OpenOrSelfTag = Name Attrs? Trailer;
64
+ OpenOrSelfTag = TagName Attrs? Trailer;
65
+ # CloseTag = "/" Name space* "}" %closetag;
66
+ CloseTag = "/" TagName space* "}" %closetag;
67
+
68
+ SomeTag = '{' space* (OpenOrSelfTag | CloseTag);
69
+
70
+ main := |*
71
+ SomeTag => {
72
+ tag = {:prefix=>@prefix, :name=>@starttag, :flavor => @flavor, :attrs => @attrs}
73
+ @prefix = nil
74
+ @name = nil
75
+ @flavor = :tasteless
76
+ @attrs = {}
77
+ @nodes << tag << ''
78
+ fbreak;
79
+ };
80
+ any => {
81
+ @nodes.last << data[p]
82
+ @tagstart = p
83
+ };
84
+ *|;
85
+ }%%
86
+
87
+ module Radius
88
+ class SquiggleScanner
89
+ def operate(prefix, data)
90
+ data = Radius::OrdString.new data
91
+ buf = ""
92
+ csel = ""
93
+ @prematch = ''
94
+ @starttag = nil
95
+ @attrs = {}
96
+ @flavor = :tasteless
97
+ @cursor = 0
98
+ @tagstart = 0
99
+ @nodes = ['']
100
+ remainder = data.dup
101
+
102
+ until remainder.length == 0
103
+ p = perform_parse(prefix, remainder)
104
+ remainder = remainder[p..-1]
105
+ end
106
+
107
+ return @nodes
108
+ end
109
+
110
+ private
111
+ def perform_parse(prefix, data)
112
+ stack = []
113
+ p = 0
114
+ ts = 0
115
+ te = 0
116
+ act = 0
117
+ eof = data.length
118
+
119
+ @prefix = prefix
120
+ %% write data;
121
+ %% write init;
122
+ %% write exec;
123
+ return p
124
+ end
125
+ end
126
+ end
@@ -26,5 +26,15 @@ module Radius
26
26
  underscored_string.split('_').each { |part| string << part.capitalize }
27
27
  string
28
28
  end
29
+
30
+ if RUBY_VERSION[0,3] == '1.8'
31
+ def self.array_to_s(c)
32
+ c.to_s
33
+ end
34
+ else
35
+ def self.array_to_s(c)
36
+ c.map{|x| x.is_a?(Array) ? array_to_s(x) : x.to_s }.join
37
+ end
38
+ end
29
39
  end
30
40
  end
@@ -1,14 +1,8 @@
1
- module Radius
2
- module Version
3
- Major = '0'
4
- Minor = '6'
5
- Tiny = '1'
6
-
7
- class << self
8
- def to_s
9
- [Major, Minor, Tiny].join('.')
10
- end
11
- alias :to_str :to_s
1
+ module Radius #:nodoc:
2
+ def self.version
3
+ @version ||= begin
4
+ filename = File.join(File.dirname(__FILE__), '..', '..', 'VERSION')
5
+ IO.read(filename).strip
12
6
  end
13
7
  end
14
- end
8
+ end
@@ -0,0 +1,22 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gem|
4
+ gem.name = "radius"
5
+ gem.summary = "A tag-based templating language for Ruby."
6
+ gem.description = "Radius is a powerful tag-based template language for Ruby inspired by the template languages used in MovableType and TextPattern. It uses tags similar to XML, but can be used to generate any form of plain text (HTML, e-mail, etc...)."
7
+ gem.email = "me@johnwlong.com"
8
+ gem.homepage = "http://github.com/jlong/radius"
9
+ gem.authors = [
10
+ "John W. Long (me@johnwlong.com)",
11
+ "David Chelimsky (dchelimsky@gmail.com)",
12
+ "Bryce Kerley (bkerley@brycekerley.net)"
13
+ ]
14
+ gem.files = FileList["[A-Z]*", "{bin,lib,tasks,test}/**/*"].exclude("tmp",'*.rbc','*.dot')
15
+ gem.extra_rdoc_files = ['README.rdoc', 'QUICKSTART.rdoc', 'LICENSE', 'CHANGELOG']
16
+ gem.add_development_dependency('RedCloth')
17
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
18
+ end
19
+ Jeweler::GemcutterTasks.new
20
+ rescue LoadError
21
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
22
+ end
@@ -0,0 +1,13 @@
1
+ require 'rake/rdoctask'
2
+ Rake::RDocTask.new do |rdoc|
3
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
4
+
5
+ rdoc.rdoc_dir = 'rdoc'
6
+ rdoc.title = "Radius #{version}"
7
+ rdoc.main = "README.rdoc"
8
+ rdoc.rdoc_files.include('*.rdoc')
9
+ rdoc.rdoc_files.include('LICENSE')
10
+ rdoc.rdoc_files.include('CHANGELOG')
11
+ rdoc.rdoc_files.include('QUICKSTART.rdoc')
12
+ rdoc.rdoc_files.include('lib/**/*.rb')
13
+ end
@@ -0,0 +1,4 @@
1
+ desc "remove Rubinius rbc files"
2
+ task "rubinius:clean" do
3
+ (Dir['**/*.rbc']).each { |f| rm f }
4
+ end
@@ -1,27 +1,79 @@
1
1
  namespace :scan do
2
- desc 'Generate the parser'
3
- task 'build' => ['lib/radius/parser/scan.rb']
2
+ desc 'Generate the parsers'
3
+ task 'build' => [
4
+ 'lib/radius/parser/scanner.rb',
5
+ 'lib/radius/parser/squiggle_scanner.rb',
6
+ 'lib/radius/parser/java_scanner.jar'
7
+ ]
4
8
 
5
- desc 'Generate a PDF state graph from the parser'
6
- task 'graph' => ['doc/scan.pdf']
9
+ desc 'Generate a PDF state graph from the parsers'
10
+ task 'graph' => ['doc/scanner.pdf', 'doc/squiggle_scanner.pdf']
7
11
 
8
- desc 'turn the scan.rl file into a ruby file'
9
- file 'lib/radius/parser/scan.rb' => ['lib/radius/parser/scan.rl'] do |t|
12
+ desc 'turn the scanner.rl file into a ruby file'
13
+ file 'lib/radius/parser/scanner.rb' => 'lib/radius/parser/scanner.rl' do |t|
10
14
  cd 'lib/radius/parser' do
11
- sh "ragel -R scan.rl"
15
+ sh "ragel -R -F1 scanner.rl"
16
+ end
17
+ end
18
+
19
+ desc 'turn the squiggle_scanner.rl file into a ruby file'
20
+ file 'lib/radius/parser/squiggle_scanner.rb' =>
21
+ ['lib/radius/parser/squiggle_scanner.rl'] \
22
+ do |t|
23
+ cd 'lib/radius/parser' do
24
+ sh "ragel -R -F1 squiggle_scanner.rl"
25
+ end
26
+ end
27
+
28
+ desc 'package JavaScanner into a jar file'
29
+ file 'lib/radius/parser/java_scanner.jar' => 'lib/radius/parser/JavaScanner.class' do
30
+ cd 'lib' do
31
+ sh "jar -cf radius/parser/java_scanner.jar radius/parser/*.class"
32
+ end
33
+ end
34
+
35
+ desc 'turn the JavaScanner.java file into a java class file'
36
+ file 'lib/radius/parser/JavaScanner.class' => 'lib/radius/parser/JavaScanner.java' do |t|
37
+ cd 'lib' do
38
+ jruby_path = ENV['JRUBY_HOME'] || '/usr/local/jruby/current'
39
+ sh "javac -cp #{jruby_path}/lib/jruby.jar radius/parser/JavaScanner.java"
40
+ end
41
+ end
42
+
43
+ desc 'turn the JavaScanner.rl file into a java source file'
44
+ file 'lib/radius/parser/JavaScanner.java' => 'lib/radius/parser/JavaScanner.rl' do |t|
45
+ cd 'lib/radius/parser' do
46
+ sh "ragel -J -F1 JavaScanner.rl"
12
47
  end
13
48
  end
14
49
 
15
50
  desc 'pdf of the ragel scanner'
16
- file 'doc/scan.pdf' => 'lib/radius/parser/scan.dot' do |t|
51
+ file 'doc/scanner.pdf' => 'lib/radius/parser/scanner.dot' do |t|
52
+ cd 'lib/radius/parser' do
53
+ sh "dot -Tpdf -o ../../../doc/scanner.pdf scanner.dot"
54
+ end
55
+ end
56
+
57
+ desc 'pdf of the ragel squiggle scanner'
58
+ file 'doc/squiggle_scanner.pdf' =>
59
+ ['lib/radius/parser/squiggle_scanner.dot'] \
60
+ do |t|
61
+ cd 'lib/radius/parser' do
62
+ sh "dot -Tpdf -o ../../../doc/squiggle_scanner.pdf squiggle_scanner.dot"
63
+ end
64
+ end
65
+
66
+ file 'lib/radius/parser/scanner.dot' => 'lib/radius/parser/scanner.rl' do |t|
17
67
  cd 'lib/radius/parser' do
18
- sh "dot -Tpdf -o ../../../doc/scan.pdf scan.dot"
68
+ sh "ragel -Vp scanner.rl > scanner.dot"
19
69
  end
20
70
  end
21
71
 
22
- file 'lib/radius/parser/scan.dot' => ['lib/radius/parser/scan.rl'] do |t|
72
+ file 'lib/radius/parser/squiggle_scanner.dot' =>
73
+ ['lib/radius/parser/squiggle_scanner.rl'] \
74
+ do |t|
23
75
  cd 'lib/radius/parser' do
24
- sh "ragel -Vp scan.rl > scan.dot"
76
+ sh "ragel -Vp squiggle_scanner.rl > squiggle_scanner.dot"
25
77
  end
26
78
  end
27
- end
79
+ end
@@ -0,0 +1,7 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << "lib" << "test"
5
+ t.test_files = FileList['test/*_test.rb']
6
+ t.verbose = true
7
+ end
@@ -0,0 +1,35 @@
1
+ $: << File.join(File.dirname(__FILE__), '..', 'lib')
2
+ require 'radius'
3
+
4
+ if RUBY_PLATFORM == 'java'
5
+ require 'java'
6
+ require 'radius/parser/jscanner'
7
+ end
8
+
9
+ require 'benchmark'
10
+
11
+ document = <<EOF
12
+ Before it all
13
+ <r:foo>
14
+ Middle Top
15
+ <r:bar />
16
+ Middle Bottom
17
+ </r:foo>
18
+ After it all
19
+ EOF
20
+
21
+ amount = 1000
22
+
23
+ Benchmark.bmbm do |bm|
24
+ bm.report('vanilla') do
25
+ scanner = Radius::Scanner.new(:scanner => Radius::Scanner)
26
+ amount.times { scanner.operate('r', document) }
27
+ end
28
+
29
+ if RUBY_PLATFORM == 'java'
30
+ bm.report('JavaScanner') do
31
+ scanner = Radius::JavaScanner.new(JRuby.runtime)
32
+ amount.times { scanner.operate('r', document) }
33
+ end
34
+ end
35
+ end
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), 'test_helper')
1
+ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
2
 
3
3
  class RadiusContextTest < Test::Unit::TestCase
4
4
  include RadiusTestHelper
@@ -27,7 +27,7 @@ class RadiusContextTest < Test::Unit::TestCase
27
27
  end
28
28
 
29
29
  def test_render_tag
30
- define_tag "hello" do |tag|
30
+ define_global_tag "hello" do |tag|
31
31
  "Hello #{tag.attr['name'] || 'World'}!"
32
32
  end
33
33
  assert_render_tag_output 'Hello World!', 'hello'
@@ -0,0 +1,63 @@
1
+ require 'thread'
2
+ require 'test/unit'
3
+ require 'radius'
4
+
5
+ class MultithreadTest < Test::Unit::TestCase
6
+
7
+ def setup
8
+ Thread.abort_on_exception
9
+ @context = Radius::Context.new do |c|
10
+ c.define_tag('thread') do |tag|
11
+ "#{tag.locals.thread_id} / #{tag.globals.object_id}"
12
+ end
13
+ end
14
+ end
15
+
16
+ if RUBY_PLATFORM == 'java'
17
+ require 'java'
18
+ # call once before the thread to keep from using hidden require in a thread
19
+ Radius::Parser.new
20
+ def test_runs_multithreaded
21
+ lock = java.lang.String.new("lock")
22
+ threads = []
23
+ 1000.times do |t|
24
+ thread = Thread.new do
25
+ parser = Radius::Parser.new(@context, :tag_prefix => 'r')
26
+ parser.context.globals.thread_id = Thread.current.object_id
27
+ expected = "#{Thread.current.object_id} / "+
28
+ "#{parser.context.globals.object_id}"
29
+ actual = parser.parse('<r:thread />')
30
+ assert_equal expected, actual
31
+ end
32
+ lock.synchronized do
33
+ threads << thread
34
+ end
35
+ end
36
+ lock.synchronized do
37
+ threads.each{|t| t.join }
38
+ end
39
+ end
40
+ else
41
+ def test_runs_multithreaded
42
+ threads = []
43
+ mute = Mutex.new
44
+ 1000.times do |t|
45
+ thread = Thread.new do
46
+ parser = Radius::Parser.new(@context, :tag_prefix => 'r')
47
+ parser.context.globals.thread_id = Thread.current.object_id
48
+ expected = "#{Thread.current.object_id} / "+
49
+ "#{parser.context.globals.object_id}"
50
+ actual = parser.parse('<r:thread />')
51
+ assert_equal expected, actual
52
+ end
53
+ mute.synchronize do
54
+ threads << thread
55
+ end
56
+ end
57
+ mute.synchronize do
58
+ threads.each{|t| t.join }
59
+ end
60
+ end
61
+ end
62
+
63
+ end
@@ -0,0 +1,18 @@
1
+ require 'test/unit'
2
+ require 'radius'
3
+
4
+ class RadiusOrdStringTest < Test::Unit::TestCase
5
+
6
+ def test_string_slice_integer
7
+ str = Radius::OrdString.new "abc"
8
+ assert_equal str[0], 97
9
+ assert_equal str[1], 98
10
+ assert_equal str[2], 99
11
+ end
12
+
13
+ def test_string_slice_range
14
+ str = Radius::OrdString.new "abc"
15
+ assert_equal str[0..-1], "abc"
16
+ end
17
+
18
+ end
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), 'test_helper')
1
+ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
2
 
3
3
  class RadiusParserTest < Test::Unit::TestCase
4
4
  include RadiusTestHelper
@@ -238,16 +238,33 @@ class RadiusParserTest < Test::Unit::TestCase
238
238
  end
239
239
 
240
240
  def test_parse_with_default_tag_prefix
241
- define_tag("hello") { |tag| "Hello world!" }
242
241
  @parser = Radius::Parser.new(@context)
242
+ define_tag("hello") { |tag| "Hello world!" }
243
243
  assert_equal "<p>Hello world!</p>", @parser.parse('<p><radius:hello /></p>')
244
244
  end
245
245
 
246
246
  def test_parse_with_other_radius_like_tags
247
- define_tag('hello') { "hello" }
248
247
  @parser = Radius::Parser.new(@context, :tag_prefix => "ralph")
248
+ define_tag('hello') { "hello" }
249
249
  assert_equal "<r:ralph:hello />", @parser.parse("<r:ralph:hello />")
250
250
  end
251
+
252
+ def test_copyin_global_values
253
+ @context.globals.foo = 'bar'
254
+ assert_equal 'bar', Radius::Parser.new(@context).context.globals.foo
255
+ end
256
+
257
+ def test_does_not_pollute_copied_globals
258
+ @context.globals.foo = 'bar'
259
+ parser = Radius::Parser.new(@context)
260
+ parser.context.globals.foo = '[baz]'
261
+ assert_equal 'bar', @context.globals.foo
262
+ end
263
+
264
+ def test_parse_with_other_namespaces
265
+ @parser = Radius::Parser.new(@context, :tag_prefix => 'r')
266
+ assert_equal "<fb:test>hello world</fb:test>", @parser.parse("<fb:test>hello world</fb:test>")
267
+ end
251
268
 
252
269
  protected
253
270
 
@@ -287,4 +304,4 @@ class RadiusParserTest < Test::Unit::TestCase
287
304
  UserWithAttributes.new('John', 25, 'test@johnwlong.com')
288
305
  end
289
306
 
290
- end
307
+ end