radiantcms-couchrest_model 0.1.6 → 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- data/radiantcms-couchrest_model.gemspec +9 -3
- data/vendor/radius/CHANGELOG +4 -22
- data/vendor/radius/QUICKSTART +2 -2
- data/vendor/radius/README +3 -95
- data/vendor/radius/Rakefile +43 -73
- data/vendor/radius/lib/radius19.rb +24 -0
- data/vendor/radius/test/context_test.rb +61 -0
- data/vendor/radius/test/dostruct_test.rb +53 -0
- data/vendor/radius/test/{radius_test.rb → parser_test.rb} +2 -87
- data/vendor/radius/test/tagbinding_test.rb +50 -0
- data/vendor/radius/test/tagdefs_test.rb +61 -0
- data/vendor/radius/test/test_helper.rb +25 -0
- data/vendor/radius/test/util_test.rb +25 -0
- metadata +10 -4
- data/vendor/radius/lib/radius.rb +0 -502
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{radiantcms-couchrest_model}
|
5
|
-
s.version = "0.1.
|
5
|
+
s.version = "0.1.7"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["davide-malagoli"]
|
@@ -2858,10 +2858,16 @@ a general purpose content managment system--not merely a blogging engine.}
|
|
2858
2858
|
"vendor/radius/ROADMAP",
|
2859
2859
|
"vendor/radius/CHANGELOG",
|
2860
2860
|
"vendor/radius/lib",
|
2861
|
-
"vendor/radius/lib/
|
2861
|
+
"vendor/radius/lib/radius19.rb",
|
2862
2862
|
"vendor/radius/README",
|
2863
2863
|
"vendor/radius/test",
|
2864
|
-
"vendor/radius/test/
|
2864
|
+
"vendor/radius/test/context_test.rb",
|
2865
|
+
"vendor/radius/test/dostruct_test.rb",
|
2866
|
+
"vendor/radius/test/parser_test.rb",
|
2867
|
+
"vendor/radius/test/tagbinding_test.rb",
|
2868
|
+
"vendor/radius/test/tagdefs_test.rb",
|
2869
|
+
"vendor/radius/test/util_test.rb",
|
2870
|
+
"vendor/radius/test/test_helper.rb",
|
2865
2871
|
"vendor/radius/Rakefile",
|
2866
2872
|
"vendor/radius/QUICKSTART",
|
2867
2873
|
"vendor/rack-cache",
|
data/vendor/radius/CHANGELOG
CHANGED
@@ -1,25 +1,7 @@
|
|
1
1
|
= Change Log
|
2
2
|
|
3
|
-
=== 0.5.
|
4
|
-
*
|
5
|
-
tag of the double tag if both contained attributes.
|
3
|
+
=== 0.5.3
|
4
|
+
* Patched to work under Ruby 1.9
|
6
5
|
|
7
|
-
=== 0.5.
|
8
|
-
*
|
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.
|
6
|
+
=== 0.5.2
|
7
|
+
* Original import from Radius (Ruby 1.8)
|
data/vendor/radius/QUICKSTART
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
Before you can parse a template with Radius you need to create a Context object which defines
|
7
7
|
the tags that will be used in the template. This is actually quite simple:
|
8
8
|
|
9
|
-
require '
|
9
|
+
require 'radius19'
|
10
10
|
|
11
11
|
context = Context.new
|
12
12
|
context.define_tag "hello" do |tag|
|
@@ -320,4 +320,4 @@ A deep understanding of tag specificity is not necessary to be effective with
|
|
320
320
|
Radius. For the most part you will find that Radius resolves tags precisely the
|
321
321
|
way that you would expect. If you find this section confusing forget about it and
|
322
322
|
refer back to it if you find that tags are resolving differently from the way that
|
323
|
-
you expected.
|
323
|
+
you expected.
|
data/vendor/radius/README
CHANGED
@@ -1,97 +1,5 @@
|
|
1
|
-
=
|
1
|
+
= Radius19 for radiantcms-couchrest_model
|
2
2
|
|
3
|
-
|
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...).
|
3
|
+
Based on the originalwork of Adrian Madrid (aemadrid@gmail.com)
|
7
4
|
|
8
|
-
|
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
|
5
|
+
on https://github.com/aemadrid/radius19/
|
data/vendor/radius/Rakefile
CHANGED
@@ -1,86 +1,56 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require 'rake
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
RUBY_FORGE_PACKAGEID = '1538'
|
15
|
-
|
16
|
-
RDOC_TITLE = "Radius -- Powerful Tag-Based Templates"
|
17
|
-
RDOC_EXTRAS = ["README", "QUICKSTART", "ROADMAP", "CHANGELOG"]
|
18
|
-
|
19
|
-
task :default => :test
|
20
|
-
|
21
|
-
Rake::TestTask.new do |t|
|
22
|
-
t.pattern = 'test/**/*_test.rb'
|
23
|
-
end
|
24
|
-
|
25
|
-
Rake::RDocTask.new do |rd|
|
26
|
-
rd.title = 'Radius -- Powerful Tag-Based Templates'
|
27
|
-
rd.main = "README"
|
28
|
-
rd.rdoc_files.include("lib/**/*.rb")
|
29
|
-
rd.rdoc_files.include(RDOC_EXTRAS)
|
30
|
-
rd.rdoc_dir = 'doc'
|
31
|
-
end
|
32
|
-
|
33
|
-
spec = Gem::Specification.new do |s|
|
34
|
-
s.name = PKG_NAME
|
35
|
-
s.version = PKG_VERSION
|
36
|
-
s.summary = 'Powerful tag-based template system.'
|
37
|
-
s.description = "Radius is a small, but powerful tag-based template language for Ruby\nsimilar to the ones used in MovableType and TextPattern. It has tags\nsimilar to HTML or XML, but can be used to generate any form of plain\ntext (not just HTML)."
|
38
|
-
s.homepage = 'http://radius.rubyforge.org'
|
39
|
-
s.rubyforge_project = RUBY_FORGE_PROJECT
|
40
|
-
s.platform = Gem::Platform::RUBY
|
41
|
-
s.requirements << 'none'
|
42
|
-
s.require_path = 'lib'
|
43
|
-
s.autorequire = 'radius'
|
44
|
-
s.has_rdoc = true
|
45
|
-
s.rdoc_options << '--title' << RDOC_TITLE << '--line-numbers' << '--main' << 'README'
|
46
|
-
s.extra_rdoc_files = RDOC_EXTRAS
|
47
|
-
files = FileList['**/*']
|
48
|
-
files.exclude 'doc'
|
49
|
-
files.exclude '**/._*'
|
50
|
-
s.files = files.to_a
|
51
|
-
end
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "radius19"
|
8
|
+
gem.summary = %Q{A small, but powerful tag-based template language for Ruby modeled after the ones used in MovableType and TextPattern. It has tags similar to XML, but can be used to generate any form of plain text (HTML, e-mail, etc...) adapted to work on Ruby 1.9.}
|
9
|
+
gem.email = "aemadrid@gmail.com"
|
10
|
+
gem.homepage = "http://github.com/aemadrid/radius19"
|
11
|
+
gem.authors = ["Adrian Madrid", "John W. Long"]
|
12
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
13
|
+
end
|
52
14
|
|
53
|
-
|
54
|
-
|
55
|
-
pkg.need_tar = true
|
15
|
+
rescue LoadError
|
16
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
56
17
|
end
|
57
18
|
|
58
|
-
|
59
|
-
|
60
|
-
|
19
|
+
require 'rake/testtask'
|
20
|
+
Rake::TestTask.new(:test) do |test|
|
21
|
+
test.libs << 'lib' << 'test'
|
22
|
+
test.pattern = 'test/**/*_test.rb'
|
23
|
+
test.verbose = true
|
61
24
|
end
|
62
25
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
26
|
+
begin
|
27
|
+
require 'rcov/rcovtask'
|
28
|
+
Rcov::RcovTask.new do |test|
|
29
|
+
test.libs << 'test'
|
30
|
+
test.pattern = 'test/**/*_test.rb'
|
31
|
+
test.verbose = true
|
32
|
+
end
|
33
|
+
rescue LoadError
|
34
|
+
task :rcov do
|
35
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
69
36
|
end
|
70
37
|
end
|
71
38
|
|
72
|
-
# --- Ruby forge release manager by florian gross -------------------------------------------------
|
73
|
-
#
|
74
|
-
# task found in Tobias Luetke's library 'liquid'
|
75
|
-
#
|
76
39
|
|
77
|
-
|
78
|
-
task :release => [:gem, :package] do
|
79
|
-
files = ["gem", "tgz", "zip"].map { |ext| "pkg/#{PKG_FILE_NAME}.#{ext}" }
|
40
|
+
task :default => :test
|
80
41
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
42
|
+
require 'rake/rdoctask'
|
43
|
+
Rake::RDocTask.new do |rdoc|
|
44
|
+
if File.exist?('VERSION.yml')
|
45
|
+
config = YAML.load(File.read('VERSION.yml'))
|
46
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
47
|
+
else
|
48
|
+
version = ""
|
85
49
|
end
|
50
|
+
|
51
|
+
rdoc.rdoc_dir = 'rdoc'
|
52
|
+
rdoc.title = "radius19 #{version}"
|
53
|
+
rdoc.rdoc_files.include('README*')
|
54
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
86
55
|
end
|
56
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2006, John W. Long
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
5
|
+
# software and associated documentation files (the "Software"), to deal in the Software
|
6
|
+
# without restriction, including without limitation the rights to use, copy, modify,
|
7
|
+
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
# permit persons to whom the Software is furnished to do so, subject to the following
|
9
|
+
# conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in all copies
|
12
|
+
# or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
15
|
+
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
16
|
+
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
17
|
+
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
18
|
+
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
19
|
+
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
|
+
#++
|
21
|
+
|
22
|
+
dir = File.join(File.dirname(__FILE__), 'radius')
|
23
|
+
require_files = %w{errors tagdefs dostruct tagbinding context parsetag parser util}
|
24
|
+
require_files.each {|f| require File.join(dir, f)}
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class RadiusContextTest < Test::Unit::TestCase
|
4
|
+
include RadiusTestHelper
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@context = new_context
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_initialize
|
11
|
+
@context = Radius::Context.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_initialize_with_block
|
15
|
+
@context = Radius::Context.new do |c|
|
16
|
+
assert_kind_of Radius::Context, c
|
17
|
+
c.define_tag('test') { 'just a test' }
|
18
|
+
end
|
19
|
+
assert_not_equal Hash.new, @context.definitions
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_with
|
23
|
+
got = @context.with do |c|
|
24
|
+
assert_equal @context, c
|
25
|
+
end
|
26
|
+
assert_equal @context, got
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_render_tag
|
30
|
+
define_tag "hello" do |tag|
|
31
|
+
"Hello #{tag.attr['name'] || 'World'}!"
|
32
|
+
end
|
33
|
+
assert_render_tag_output 'Hello World!', 'hello'
|
34
|
+
assert_render_tag_output 'Hello John!', 'hello', 'name' => 'John'
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_render_tag__undefined_tag
|
38
|
+
e = assert_raises(Radius::UndefinedTagError) { @context.render_tag('undefined_tag') }
|
39
|
+
assert_equal "undefined tag `undefined_tag'", e.message
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_tag_missing
|
43
|
+
class << @context
|
44
|
+
def tag_missing(tag, attr, &block)
|
45
|
+
"undefined tag `#{tag}' with attributes #{attr.inspect}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
text = ''
|
50
|
+
expected = %{undefined tag `undefined_tag' with attributes {"cool"=>"beans"}}
|
51
|
+
assert_nothing_raised { text = @context.render_tag('undefined_tag', 'cool' => 'beans') }
|
52
|
+
assert_equal expected, text
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def assert_render_tag_output(output, *render_tag_params)
|
58
|
+
assert_equal output, @context.render_tag(*render_tag_params)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class TestDOS
|
4
|
+
attr_accessor :name
|
5
|
+
end
|
6
|
+
|
7
|
+
class RadiusDelegatingOpenStructtTest < Test::Unit::TestCase
|
8
|
+
def new_dos(obj = nil)
|
9
|
+
Radius::DelegatingOpenStruct.new obj
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_initialize_wo_object
|
13
|
+
o = new_dos nil
|
14
|
+
assert_nil o.object
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_initialize_w_object
|
18
|
+
x = TestDOS.new
|
19
|
+
o = new_dos x
|
20
|
+
assert_equal o.object, x
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_assign_and_read_vars
|
24
|
+
o = new_dos
|
25
|
+
o.age = 15
|
26
|
+
o.height = 3.5
|
27
|
+
assert_equal o.age, 15
|
28
|
+
assert_equal o.height, 3.5
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_read_object
|
32
|
+
o = new_dos TestDOS.new
|
33
|
+
o.object.name = 'Peter'
|
34
|
+
assert_equal o.name, 'Peter'
|
35
|
+
assert_equal o.object.name, 'Peter'
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_read_and_assign_mixed
|
39
|
+
o = new_dos TestDOS.new
|
40
|
+
o.object.name = 'Peter'
|
41
|
+
o.age = 15
|
42
|
+
assert_equal o.name, 'Peter'
|
43
|
+
assert_equal o.object.name, 'Peter'
|
44
|
+
assert_equal o.age, 15
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_raise_on_unknown_method
|
48
|
+
o = new_dos TestDOS.new
|
49
|
+
assert_raise NoMethodError do
|
50
|
+
o.age
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -1,83 +1,4 @@
|
|
1
|
-
require '
|
2
|
-
require 'radius'
|
3
|
-
|
4
|
-
module RadiusTestHelper
|
5
|
-
class TestContext < Radius::Context; end
|
6
|
-
|
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 }
|
12
|
-
c.define_tag("echo" ) { |tag| tag.attr['value'] }
|
13
|
-
c.define_tag("wrap" ) { |tag| "[#{tag.expand}]" }
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def define_tag(name, options = {}, &block)
|
18
|
-
@context.define_tag name, options, &block
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
class RadiusContextTest < Test::Unit::TestCase
|
23
|
-
include RadiusTestHelper
|
24
|
-
|
25
|
-
def setup
|
26
|
-
@context = new_context
|
27
|
-
end
|
28
|
-
|
29
|
-
def test_initialize
|
30
|
-
@context = Radius::Context.new
|
31
|
-
end
|
32
|
-
|
33
|
-
def test_initialize_with_block
|
34
|
-
@context = Radius::Context.new do |c|
|
35
|
-
assert_kind_of Radius::Context, c
|
36
|
-
c.define_tag('test') { 'just a test' }
|
37
|
-
end
|
38
|
-
assert_not_equal Hash.new, @context.definitions
|
39
|
-
end
|
40
|
-
|
41
|
-
def test_with
|
42
|
-
got = @context.with do |c|
|
43
|
-
assert_equal @context, c
|
44
|
-
end
|
45
|
-
assert_equal @context, got
|
46
|
-
end
|
47
|
-
|
48
|
-
def test_render_tag
|
49
|
-
define_tag "hello" do |tag|
|
50
|
-
"Hello #{tag.attr['name'] || 'World'}!"
|
51
|
-
end
|
52
|
-
assert_render_tag_output 'Hello World!', 'hello'
|
53
|
-
assert_render_tag_output 'Hello John!', 'hello', 'name' => 'John'
|
54
|
-
end
|
55
|
-
|
56
|
-
def test_render_tag__undefined_tag
|
57
|
-
e = assert_raises(Radius::UndefinedTagError) { @context.render_tag('undefined_tag') }
|
58
|
-
assert_equal "undefined tag `undefined_tag'", e.message
|
59
|
-
end
|
60
|
-
|
61
|
-
def test_tag_missing
|
62
|
-
class << @context
|
63
|
-
def tag_missing(tag, attr, &block)
|
64
|
-
"undefined tag `#{tag}' with attributes #{attr.inspect}"
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
text = ''
|
69
|
-
expected = %{undefined tag `undefined_tag' with attributes {"cool"=>"beans"}}
|
70
|
-
assert_nothing_raised { text = @context.render_tag('undefined_tag', 'cool' => 'beans') }
|
71
|
-
assert_equal expected, text
|
72
|
-
end
|
73
|
-
|
74
|
-
private
|
75
|
-
|
76
|
-
def assert_render_tag_output(output, *render_tag_params)
|
77
|
-
assert_equal output, @context.render_tag(*render_tag_params)
|
78
|
-
end
|
79
|
-
|
80
|
-
end
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
81
2
|
|
82
3
|
class RadiusParserTest < Test::Unit::TestCase
|
83
4
|
include RadiusTestHelper
|
@@ -197,12 +118,6 @@ class RadiusParserTest < Test::Unit::TestCase
|
|
197
118
|
define_tag('hello') { |tag| tag.render('test', tag.attr) }
|
198
119
|
assert_parse_output 'Hello John!', '<r:hello name="John" />'
|
199
120
|
end
|
200
|
-
|
201
|
-
def test_accessing_tag_attributes_through_tag_indexer
|
202
|
-
define_tag('test') { |tag| "Hello #{tag['name']}!" }
|
203
|
-
assert_parse_output 'Hello John!', '<r:test name="John" />'
|
204
|
-
end
|
205
|
-
|
206
121
|
def test_parse_tag__binding_render_tag_with_block
|
207
122
|
define_tag('test') { |tag| "Hello #{tag.expand}!" }
|
208
123
|
define_tag('hello') { |tag| tag.render('test') { tag.expand } }
|
@@ -323,5 +238,5 @@ class RadiusParserTest < Test::Unit::TestCase
|
|
323
238
|
def user_with_attributes
|
324
239
|
UserWithAttributes.new('John', 25, 'test@johnwlong.com')
|
325
240
|
end
|
326
|
-
|
241
|
+
|
327
242
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class RadiusTagBindingTest < Test::Unit::TestCase
|
4
|
+
include RadiusTestHelper
|
5
|
+
|
6
|
+
def new_tag_binding(opts = {})
|
7
|
+
opts = {
|
8
|
+
:cnx => new_context,
|
9
|
+
:locals => Radius::DelegatingOpenStruct.new,
|
10
|
+
:name => :test,
|
11
|
+
:attrs => {},
|
12
|
+
:blk => Proc.new { 'hello!'}
|
13
|
+
}.update(opts)
|
14
|
+
Radius::TagBinding.new opts[:cnx], opts[:locals], opts[:name], opts[:attrs], opts[:blk]
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_initialize
|
18
|
+
nc = new_context
|
19
|
+
ls = Radius::DelegatingOpenStruct.new
|
20
|
+
nm = :xyz
|
21
|
+
as = { :a => 1, :b => 2 }
|
22
|
+
bk = Proc.new { 'hello!'}
|
23
|
+
tb = new_tag_binding :cnx => nc, :locals => ls, :name => nm, :attrs => as, :blk => bk
|
24
|
+
assert_equal tb.context, nc
|
25
|
+
assert_equal tb.locals, ls
|
26
|
+
assert_equal tb.name, nm
|
27
|
+
assert_equal tb.attributes, as
|
28
|
+
assert_equal tb.attr, as
|
29
|
+
assert_equal tb.block, bk
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_expand
|
33
|
+
tb = new_tag_binding
|
34
|
+
assert_equal tb.expand, 'hello!'
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_single_double
|
38
|
+
tb1 = new_tag_binding :blk => Proc.new{ 'hello!'}
|
39
|
+
assert_equal tb1.single?, false
|
40
|
+
assert_equal tb1.double?, true
|
41
|
+
tb2 = new_tag_binding :blk => nil
|
42
|
+
assert_equal tb2.single?, true
|
43
|
+
assert_equal tb2.double?, false
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_globals
|
47
|
+
tb = new_tag_binding
|
48
|
+
assert_equal tb.globals, tb.context.globals
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class ARLike < Radius::DelegatingOpenStruct
|
4
|
+
def attributes
|
5
|
+
@hash
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class RadiusTagDefinitionsTest < Test::Unit::TestCase
|
10
|
+
include RadiusTestHelper
|
11
|
+
|
12
|
+
def new_tag_factory
|
13
|
+
Radius::TagDefinitions::TagFactory.new new_context
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_initialize
|
17
|
+
new_tag_factory
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_prepare_options_w_for
|
21
|
+
tf = new_tag_factory
|
22
|
+
ar = ARLike.new
|
23
|
+
ar.x, ar.y, ar.z = 1, 2, 3
|
24
|
+
res = tf.send :prepare_options, :test, { 'for' => ar, 'other' => 1, 'more' => 'mas' }
|
25
|
+
assert_equal res.keys.size, 5
|
26
|
+
assert_equal res[:for], ar
|
27
|
+
assert_equal res[:expose].size, 3
|
28
|
+
assert res[:expose].include?(:x)
|
29
|
+
assert res[:expose].include?(:y)
|
30
|
+
assert res[:expose].include?(:z)
|
31
|
+
assert_equal res[:attributes], true
|
32
|
+
assert_equal res[:other], 1
|
33
|
+
assert_equal res[:more], 'mas'
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_prepare_options_wo_for
|
37
|
+
tf = new_tag_factory
|
38
|
+
res = tf.send :prepare_options, :test, { 'other' => 1, 'more' => 'mas' }
|
39
|
+
assert_equal res.keys.size, 4
|
40
|
+
assert_equal res[:expose], []
|
41
|
+
assert_equal res[:attributes], false
|
42
|
+
assert_equal res[:other], 1
|
43
|
+
assert_equal res[:more], 'mas'
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_validate_params
|
47
|
+
tf = new_tag_factory
|
48
|
+
assert_raise(ArgumentError) { tf.send :validate_params, :echo, {} }
|
49
|
+
assert_raise(ArgumentError) { tf.send :validate_params, :echo, { :expose => [:x]} }
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_expand_array_option
|
53
|
+
tf = new_tag_factory
|
54
|
+
assert_equal tf.send(:expand_array_option, ['a', 'b', nil, 'c']), [:a, :b, :c]
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_last_part
|
58
|
+
tf = new_tag_factory
|
59
|
+
assert_equal tf.send(:last_part, 'a:b:c'), 'c'
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require File.dirname(__FILE__) + '/../lib/radius19'
|
4
|
+
|
5
|
+
class Test::Unit::TestCase
|
6
|
+
end
|
7
|
+
|
8
|
+
module RadiusTestHelper
|
9
|
+
class TestContext < Radius::Context; end
|
10
|
+
|
11
|
+
def new_context
|
12
|
+
Radius::Context.new do |c|
|
13
|
+
c.define_tag("reverse" ) { |tag| tag.expand.reverse }
|
14
|
+
c.define_tag("capitalize") { |tag| tag.expand.upcase }
|
15
|
+
c.define_tag("attr" ) { |tag| tag.attr.inspect }
|
16
|
+
c.define_tag("echo" ) { |tag| tag.attr['value'] }
|
17
|
+
c.define_tag("wrap" ) { |tag| "[#{tag.expand}]" }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def define_tag(name, options = {}, &block)
|
22
|
+
@context.define_tag name, options, &block
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class RadiusUtilTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_symbolize_keys
|
6
|
+
h = Radius::Util.symbolize_keys({ 'a' => 1, :b => 2 })
|
7
|
+
assert_equal h[:a], 1
|
8
|
+
assert_equal h[:b], 2
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_impartial_hash_delete
|
12
|
+
h = { 'a' => 1, :b => 2 }
|
13
|
+
assert_equal Radius::Util.impartial_hash_delete(h, :a), 1
|
14
|
+
assert_equal Radius::Util.impartial_hash_delete(h, 'b'), 2
|
15
|
+
assert_equal h.empty?, true
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_constantize
|
19
|
+
assert_equal Radius::Util.constantize('String'), String
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_camelize
|
23
|
+
assert_equal Radius::Util.camelize('ab_cd_ef'), 'AbCdEf'
|
24
|
+
end
|
25
|
+
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 7
|
9
|
+
version: 0.1.7
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- davide-malagoli
|
@@ -2387,9 +2387,15 @@ files:
|
|
2387
2387
|
- vendor/rails/activeresource/Rakefile
|
2388
2388
|
- vendor/radius/ROADMAP
|
2389
2389
|
- vendor/radius/CHANGELOG
|
2390
|
-
- vendor/radius/lib/
|
2390
|
+
- vendor/radius/lib/radius19.rb
|
2391
2391
|
- vendor/radius/README
|
2392
|
-
- vendor/radius/test/
|
2392
|
+
- vendor/radius/test/context_test.rb
|
2393
|
+
- vendor/radius/test/dostruct_test.rb
|
2394
|
+
- vendor/radius/test/parser_test.rb
|
2395
|
+
- vendor/radius/test/tagbinding_test.rb
|
2396
|
+
- vendor/radius/test/tagdefs_test.rb
|
2397
|
+
- vendor/radius/test/util_test.rb
|
2398
|
+
- vendor/radius/test/test_helper.rb
|
2393
2399
|
- vendor/radius/Rakefile
|
2394
2400
|
- vendor/radius/QUICKSTART
|
2395
2401
|
- vendor/rack-cache/COPYING
|
data/vendor/radius/lib/radius.rb
DELETED
@@ -1,502 +0,0 @@
|
|
1
|
-
#--
|
2
|
-
# Copyright (c) 2006, John W. Long
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
5
|
-
# software and associated documentation files (the "Software"), to deal in the Software
|
6
|
-
# without restriction, including without limitation the rights to use, copy, modify,
|
7
|
-
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
-
# permit persons to whom the Software is furnished to do so, subject to the following
|
9
|
-
# conditions:
|
10
|
-
#
|
11
|
-
# The above copyright notice and this permission notice shall be included in all copies
|
12
|
-
# or substantial portions of the Software.
|
13
|
-
#
|
14
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
15
|
-
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
16
|
-
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
17
|
-
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
18
|
-
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
19
|
-
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
|
-
#++
|
21
|
-
module Radius
|
22
|
-
# Abstract base class for all parsing errors.
|
23
|
-
class ParseError < StandardError
|
24
|
-
end
|
25
|
-
|
26
|
-
# Occurs when Parser cannot find an end tag for a given tag in a template or when
|
27
|
-
# tags are miss-matched in a template.
|
28
|
-
class MissingEndTagError < ParseError
|
29
|
-
# Create a new MissingEndTagError object for +tag_name+.
|
30
|
-
def initialize(tag_name)
|
31
|
-
super("end tag not found for start tag `#{tag_name}'")
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
# Occurs when Context#render_tag cannot find the specified tag on a Context.
|
36
|
-
class UndefinedTagError < ParseError
|
37
|
-
# Create a new UndefinedTagError object for +tag_name+.
|
38
|
-
def initialize(tag_name)
|
39
|
-
super("undefined tag `#{tag_name}'")
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
module TagDefinitions # :nodoc:
|
44
|
-
class TagFactory # :nodoc:
|
45
|
-
def initialize(context)
|
46
|
-
@context = context
|
47
|
-
end
|
48
|
-
|
49
|
-
def define_tag(name, options, &block)
|
50
|
-
options = prepare_options(name, options)
|
51
|
-
validate_params(name, options, &block)
|
52
|
-
construct_tag_set(name, options, &block)
|
53
|
-
expose_methods_as_tags(name, options)
|
54
|
-
end
|
55
|
-
|
56
|
-
protected
|
57
|
-
|
58
|
-
# Adds the tag definition to the context. Override in subclasses to add additional tags
|
59
|
-
# (child tags) when the tag is created.
|
60
|
-
def construct_tag_set(name, options, &block)
|
61
|
-
if block
|
62
|
-
@context.definitions[name.to_s] = block
|
63
|
-
else
|
64
|
-
lp = last_part(name)
|
65
|
-
@context.define_tag(name) do |tag|
|
66
|
-
if tag.single?
|
67
|
-
options[:for]
|
68
|
-
else
|
69
|
-
tag.locals.send("#{ lp }=", options[:for]) unless options[:for].nil?
|
70
|
-
tag.expand
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
# Normalizes options pased to tag definition. Override in decendants to preform
|
77
|
-
# additional normalization.
|
78
|
-
def prepare_options(name, options)
|
79
|
-
options = Util.symbolize_keys(options)
|
80
|
-
options[:expose] = expand_array_option(options[:expose])
|
81
|
-
object = options[:for]
|
82
|
-
options[:attributes] = object.respond_to?(:attributes) unless options.has_key? :attributes
|
83
|
-
options[:expose] += object.attributes.keys if options[:attributes]
|
84
|
-
options
|
85
|
-
end
|
86
|
-
|
87
|
-
# Validates parameters passed to tag definition. Override in decendants to add custom
|
88
|
-
# validations.
|
89
|
-
def validate_params(name, options, &block)
|
90
|
-
unless options.has_key? :for
|
91
|
-
raise ArgumentError.new("tag definition must contain a :for option or a block") unless block
|
92
|
-
raise ArgumentError.new("tag definition must contain a :for option when used with the :expose option") unless options[:expose].empty?
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
# Exposes the methods of an object as child tags.
|
97
|
-
def expose_methods_as_tags(name, options)
|
98
|
-
options[:expose].each do |method|
|
99
|
-
tag_name = "#{name}:#{method}"
|
100
|
-
lp = last_part(name)
|
101
|
-
@context.define_tag(tag_name) do |tag|
|
102
|
-
object = tag.locals.send(lp)
|
103
|
-
object.send(method)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
protected
|
109
|
-
|
110
|
-
def expand_array_option(value)
|
111
|
-
[*value].compact.map { |m| m.to_s.intern }
|
112
|
-
end
|
113
|
-
|
114
|
-
def last_part(name)
|
115
|
-
name.split(':').last
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
class DelegatingOpenStruct # :nodoc:
|
121
|
-
attr_accessor :object
|
122
|
-
|
123
|
-
def initialize(object = nil)
|
124
|
-
@object = object
|
125
|
-
@hash = {}
|
126
|
-
end
|
127
|
-
|
128
|
-
def method_missing(method, *args, &block)
|
129
|
-
symbol = (method.to_s =~ /^(.*?)=$/) ? $1.intern : method
|
130
|
-
if (0..1).include?(args.size)
|
131
|
-
if args.size == 1
|
132
|
-
@hash[symbol] = args.first
|
133
|
-
else
|
134
|
-
if @hash.has_key?(symbol)
|
135
|
-
@hash[symbol]
|
136
|
-
else
|
137
|
-
unless object.nil?
|
138
|
-
@object.send(method, *args, &block)
|
139
|
-
else
|
140
|
-
nil
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
else
|
145
|
-
super
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
#
|
151
|
-
# A tag binding is passed into each tag definition and contains helper methods for working
|
152
|
-
# with tags. Use it to gain access to the attributes that were passed to the tag, to
|
153
|
-
# render the tag contents, and to do other tasks.
|
154
|
-
#
|
155
|
-
class TagBinding
|
156
|
-
# The Context that the TagBinding is associated with. Used internally. Try not to use
|
157
|
-
# this object directly.
|
158
|
-
attr_reader :context
|
159
|
-
|
160
|
-
# The locals object for the current tag.
|
161
|
-
attr_reader :locals
|
162
|
-
|
163
|
-
# The name of the tag (as used in a template string).
|
164
|
-
attr_reader :name
|
165
|
-
|
166
|
-
# The attributes of the tag. Also aliased as TagBinding#attr.
|
167
|
-
attr_reader :attributes
|
168
|
-
alias :attr :attributes
|
169
|
-
|
170
|
-
# The render block. When called expands the contents of the tag. Use TagBinding#expand
|
171
|
-
# instead.
|
172
|
-
attr_reader :block
|
173
|
-
|
174
|
-
# Creates a new TagBinding object.
|
175
|
-
def initialize(context, locals, name, attributes, block)
|
176
|
-
@context, @locals, @name, @attributes, @block = context, locals, name, attributes, block
|
177
|
-
end
|
178
|
-
|
179
|
-
# Evaluates the current tag and returns the rendered contents.
|
180
|
-
def expand
|
181
|
-
double? ? block.call : ''
|
182
|
-
end
|
183
|
-
|
184
|
-
# Returns true if the current tag is a single tag.
|
185
|
-
def single?
|
186
|
-
block.nil?
|
187
|
-
end
|
188
|
-
|
189
|
-
# Returns true if the current tag is a container tag.
|
190
|
-
def double?
|
191
|
-
not single?
|
192
|
-
end
|
193
|
-
|
194
|
-
# The globals object from which all locals objects ultimately inherit their values.
|
195
|
-
def globals
|
196
|
-
@context.globals
|
197
|
-
end
|
198
|
-
|
199
|
-
# Returns a list of the way tags are nested around the current tag as a string.
|
200
|
-
def nesting
|
201
|
-
@context.current_nesting
|
202
|
-
end
|
203
|
-
|
204
|
-
# Fires off Context#tag_missing for the current tag.
|
205
|
-
def missing!
|
206
|
-
@context.tag_missing(name, attributes, &block)
|
207
|
-
end
|
208
|
-
|
209
|
-
# Renders the tag using the current context .
|
210
|
-
def render(tag, attributes = {}, &block)
|
211
|
-
@context.render_tag(tag, attributes, &block)
|
212
|
-
end
|
213
|
-
|
214
|
-
# Shortcut for accessing tag.attr[key]
|
215
|
-
def [](key)
|
216
|
-
attr[key]
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
#
|
221
|
-
# A context contains the tag definitions which are available for use in a template.
|
222
|
-
# See the QUICKSTART[link:files/QUICKSTART.html] for a detailed explaination its
|
223
|
-
# usage.
|
224
|
-
#
|
225
|
-
class Context
|
226
|
-
# A hash of tag definition blocks that define tags accessible on a Context.
|
227
|
-
attr_accessor :definitions # :nodoc:
|
228
|
-
attr_accessor :globals # :nodoc:
|
229
|
-
|
230
|
-
# Creates a new Context object.
|
231
|
-
def initialize(&block)
|
232
|
-
@definitions = {}
|
233
|
-
@tag_binding_stack = []
|
234
|
-
@globals = DelegatingOpenStruct.new
|
235
|
-
with(&block) if block_given?
|
236
|
-
end
|
237
|
-
|
238
|
-
# Yeild an instance of self for tag definitions:
|
239
|
-
#
|
240
|
-
# context.with do |c|
|
241
|
-
# c.define_tag 'test' do
|
242
|
-
# 'test'
|
243
|
-
# end
|
244
|
-
# end
|
245
|
-
#
|
246
|
-
def with
|
247
|
-
yield self
|
248
|
-
self
|
249
|
-
end
|
250
|
-
|
251
|
-
# Creates a tag definition on a context. Several options are available to you
|
252
|
-
# when creating a tag:
|
253
|
-
#
|
254
|
-
# +for+:: Specifies an object that the tag is in reference to. This is
|
255
|
-
# applicable when a block is not passed to the tag, or when the
|
256
|
-
# +expose+ option is also used.
|
257
|
-
#
|
258
|
-
# +expose+:: Specifies that child tags should be set for each of the methods
|
259
|
-
# contained in this option. May be either a single symbol/string or
|
260
|
-
# an array of symbols/strings.
|
261
|
-
#
|
262
|
-
# +attributes+:: Specifies whether or not attributes should be exposed
|
263
|
-
# automatically. Useful for ActiveRecord objects. Boolean. Defaults
|
264
|
-
# to +true+.
|
265
|
-
#
|
266
|
-
def define_tag(name, options = {}, &block)
|
267
|
-
type = Util.impartial_hash_delete(options, :type).to_s
|
268
|
-
klass = Util.constantize('Radius::TagDefinitions::' + Util.camelize(type) + 'TagFactory') rescue raise(ArgumentError.new("Undefined type `#{type}' in options hash"))
|
269
|
-
klass.new(self).define_tag(name, options, &block)
|
270
|
-
end
|
271
|
-
|
272
|
-
# Returns the value of a rendered tag. Used internally by Parser#parse.
|
273
|
-
def render_tag(name, attributes = {}, &block)
|
274
|
-
if name =~ /^(.+?):(.+)$/
|
275
|
-
render_tag($1) { render_tag($2, attributes, &block) }
|
276
|
-
else
|
277
|
-
tag_definition_block = @definitions[qualified_tag_name(name.to_s)]
|
278
|
-
if tag_definition_block
|
279
|
-
stack(name, attributes, block) do |tag|
|
280
|
-
tag_definition_block.call(tag).to_s
|
281
|
-
end
|
282
|
-
else
|
283
|
-
tag_missing(name, attributes, &block)
|
284
|
-
end
|
285
|
-
end
|
286
|
-
end
|
287
|
-
|
288
|
-
# Like method_missing for objects, but fired when a tag is undefined.
|
289
|
-
# Override in your own Context to change what happens when a tag is
|
290
|
-
# undefined. By default this method raises an UndefinedTagError.
|
291
|
-
def tag_missing(name, attributes, &block)
|
292
|
-
raise UndefinedTagError.new(name)
|
293
|
-
end
|
294
|
-
|
295
|
-
# Returns the state of the current render stack. Useful from inside
|
296
|
-
# a tag definition. Normally just use TagBinding#nesting.
|
297
|
-
def current_nesting
|
298
|
-
@tag_binding_stack.collect { |tag| tag.name }.join(':')
|
299
|
-
end
|
300
|
-
|
301
|
-
private
|
302
|
-
|
303
|
-
# A convienence method for managing the various parts of the
|
304
|
-
# tag binding stack.
|
305
|
-
def stack(name, attributes, block)
|
306
|
-
previous = @tag_binding_stack.last
|
307
|
-
previous_locals = previous.nil? ? @globals : previous.locals
|
308
|
-
locals = DelegatingOpenStruct.new(previous_locals)
|
309
|
-
binding = TagBinding.new(self, locals, name, attributes, block)
|
310
|
-
@tag_binding_stack.push(binding)
|
311
|
-
result = yield(binding)
|
312
|
-
@tag_binding_stack.pop
|
313
|
-
result
|
314
|
-
end
|
315
|
-
|
316
|
-
# Returns a fully qualified tag name based on state of the
|
317
|
-
# tag binding stack.
|
318
|
-
def qualified_tag_name(name)
|
319
|
-
nesting_parts = @tag_binding_stack.collect { |tag| tag.name }
|
320
|
-
nesting_parts << name unless nesting_parts.last == name
|
321
|
-
specific_name = nesting_parts.join(':') # specific_name always has the highest specificity
|
322
|
-
unless @definitions.has_key? specific_name
|
323
|
-
possible_matches = @definitions.keys.grep(/(^|:)#{name}$/)
|
324
|
-
specificity = possible_matches.inject({}) { |hash, tag| hash[numeric_specificity(tag, nesting_parts)] = tag; hash }
|
325
|
-
max = specificity.keys.max
|
326
|
-
if max != 0
|
327
|
-
specificity[max]
|
328
|
-
else
|
329
|
-
name
|
330
|
-
end
|
331
|
-
else
|
332
|
-
specific_name
|
333
|
-
end
|
334
|
-
end
|
335
|
-
|
336
|
-
# Returns the specificity for +tag_name+ at nesting defined
|
337
|
-
# by +nesting_parts+ as a number.
|
338
|
-
def numeric_specificity(tag_name, nesting_parts)
|
339
|
-
nesting_parts = nesting_parts.dup
|
340
|
-
name_parts = tag_name.split(':')
|
341
|
-
specificity = 0
|
342
|
-
value = 1
|
343
|
-
if nesting_parts.last == name_parts.last
|
344
|
-
while nesting_parts.size > 0
|
345
|
-
if nesting_parts.last == name_parts.last
|
346
|
-
specificity += value
|
347
|
-
name_parts.pop
|
348
|
-
end
|
349
|
-
nesting_parts.pop
|
350
|
-
value *= 0.1
|
351
|
-
end
|
352
|
-
specificity = 0 if (name_parts.size > 0)
|
353
|
-
end
|
354
|
-
specificity
|
355
|
-
end
|
356
|
-
end
|
357
|
-
|
358
|
-
class ParseTag # :nodoc:
|
359
|
-
def initialize(&b)
|
360
|
-
@block = b
|
361
|
-
end
|
362
|
-
|
363
|
-
def on_parse(&b)
|
364
|
-
@block = b
|
365
|
-
end
|
366
|
-
|
367
|
-
def to_s
|
368
|
-
@block.call(self)
|
369
|
-
end
|
370
|
-
end
|
371
|
-
|
372
|
-
class ParseContainerTag < ParseTag # :nodoc:
|
373
|
-
attr_accessor :name, :attributes, :contents
|
374
|
-
|
375
|
-
def initialize(name = "", attributes = {}, contents = [], &b)
|
376
|
-
@name, @attributes, @contents = name, attributes, contents
|
377
|
-
super(&b)
|
378
|
-
end
|
379
|
-
end
|
380
|
-
|
381
|
-
#
|
382
|
-
# The Radius parser. Initialize a parser with a Context object that
|
383
|
-
# defines how tags should be expanded. See the QUICKSTART[link:files/QUICKSTART.html]
|
384
|
-
# for a detailed explaination of its usage.
|
385
|
-
#
|
386
|
-
class Parser
|
387
|
-
# The Context object used to expand template tags.
|
388
|
-
attr_accessor :context
|
389
|
-
|
390
|
-
# The string that prefixes all tags that are expanded by a parser
|
391
|
-
# (the part in the tag name before the first colon).
|
392
|
-
attr_accessor :tag_prefix
|
393
|
-
|
394
|
-
# Creates a new parser object initialized with a Context.
|
395
|
-
def initialize(context = Context.new, options = {})
|
396
|
-
if context.kind_of?(Hash) and options.empty?
|
397
|
-
options = context
|
398
|
-
context = options[:context] || options['context'] || Context.new
|
399
|
-
end
|
400
|
-
options = Util.symbolize_keys(options)
|
401
|
-
@context = context
|
402
|
-
@tag_prefix = options[:tag_prefix]
|
403
|
-
end
|
404
|
-
|
405
|
-
# Parses string for tags, expands them, and returns the result.
|
406
|
-
def parse(string)
|
407
|
-
@stack = [ParseContainerTag.new { |t| t.contents.to_s }]
|
408
|
-
pre_parse(string)
|
409
|
-
@stack.last.to_s
|
410
|
-
end
|
411
|
-
|
412
|
-
protected
|
413
|
-
|
414
|
-
def pre_parse(text) # :nodoc:
|
415
|
-
re = %r{<#{@tag_prefix}:([\w:]+?)(\s+(?:\w+\s*=\s*(?:"[^"]*?"|'[^']*?')\s*)*|)>|</#{@tag_prefix}:([\w:]+?)\s*>}
|
416
|
-
if md = re.match(text)
|
417
|
-
start_tag, attr, end_tag = $1, $2, $3
|
418
|
-
@stack.last.contents << ParseTag.new { parse_individual(md.pre_match) }
|
419
|
-
remaining = md.post_match
|
420
|
-
if start_tag
|
421
|
-
parse_start_tag(start_tag, attr, remaining)
|
422
|
-
else
|
423
|
-
parse_end_tag(end_tag, remaining)
|
424
|
-
end
|
425
|
-
else
|
426
|
-
if @stack.length == 1
|
427
|
-
@stack.last.contents << ParseTag.new { parse_individual(text) }
|
428
|
-
else
|
429
|
-
raise MissingEndTagError.new(@stack.last.name)
|
430
|
-
end
|
431
|
-
end
|
432
|
-
end
|
433
|
-
|
434
|
-
def parse_start_tag(start_tag, attr, remaining) # :nodoc:
|
435
|
-
@stack.push(ParseContainerTag.new(start_tag, parse_attributes(attr)))
|
436
|
-
pre_parse(remaining)
|
437
|
-
end
|
438
|
-
|
439
|
-
def parse_end_tag(end_tag, remaining) # :nodoc:
|
440
|
-
popped = @stack.pop
|
441
|
-
if popped.name == end_tag
|
442
|
-
popped.on_parse { |t| @context.render_tag(popped.name, popped.attributes) { t.contents.to_s } }
|
443
|
-
tag = @stack.last
|
444
|
-
tag.contents << popped
|
445
|
-
pre_parse(remaining)
|
446
|
-
else
|
447
|
-
raise MissingEndTagError.new(popped.name)
|
448
|
-
end
|
449
|
-
end
|
450
|
-
|
451
|
-
def parse_individual(text) # :nodoc:
|
452
|
-
re = %r{<#{@tag_prefix}:([\w:]+?)(\s+(?:\w+\s*=\s*(?:"[^"]*?"|'[^']*?')\s*)*|)/>}
|
453
|
-
if md = re.match(text)
|
454
|
-
attr = parse_attributes($2)
|
455
|
-
replace = @context.render_tag($1, attr)
|
456
|
-
md.pre_match + replace + parse_individual(md.post_match)
|
457
|
-
else
|
458
|
-
text || ''
|
459
|
-
end
|
460
|
-
end
|
461
|
-
|
462
|
-
def parse_attributes(text) # :nodoc:
|
463
|
-
attr = {}
|
464
|
-
re = /(\w+?)\s*=\s*('|")(.*?)\2/
|
465
|
-
while md = re.match(text)
|
466
|
-
attr[$1] = $3
|
467
|
-
text = md.post_match
|
468
|
-
end
|
469
|
-
attr
|
470
|
-
end
|
471
|
-
end
|
472
|
-
|
473
|
-
module Util # :nodoc:
|
474
|
-
def self.symbolize_keys(hash)
|
475
|
-
new_hash = {}
|
476
|
-
hash.keys.each do |k|
|
477
|
-
new_hash[k.to_s.intern] = hash[k]
|
478
|
-
end
|
479
|
-
new_hash
|
480
|
-
end
|
481
|
-
|
482
|
-
def self.impartial_hash_delete(hash, key)
|
483
|
-
string = key.to_s
|
484
|
-
symbol = string.intern
|
485
|
-
value1 = hash.delete(symbol)
|
486
|
-
value2 = hash.delete(string)
|
487
|
-
value1 || value2
|
488
|
-
end
|
489
|
-
|
490
|
-
def self.constantize(camelized_string)
|
491
|
-
raise "invalid constant name `#{camelized_string}'" unless camelized_string.split('::').all? { |part| part =~ /^[A-Za-z]+$/ }
|
492
|
-
Object.module_eval(camelized_string)
|
493
|
-
end
|
494
|
-
|
495
|
-
def self.camelize(underscored_string)
|
496
|
-
string = ''
|
497
|
-
underscored_string.split('_').each { |part| string << part.capitalize }
|
498
|
-
string
|
499
|
-
end
|
500
|
-
end
|
501
|
-
|
502
|
-
end
|