zorglub 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Changelog +2 -0
- data/MIT-LICENSE +18 -0
- data/README.rdoc +55 -0
- data/Rakefile +58 -0
- data/lib/zorglub/app.rb +45 -0
- data/lib/zorglub/config.rb +66 -0
- data/lib/zorglub/node.rb +196 -0
- data/lib/zorglub/session.rb +81 -0
- data/lib/zorglub.rb +14 -0
- data/spec/app_spec.rb +43 -0
- data/spec/data/layout/default +0 -0
- data/spec/data/layout/main.spec +0 -0
- data/spec/data/view/node0/do_partial +0 -0
- data/spec/data/view/node0/do_render +0 -0
- data/spec/node_spec.rb +157 -0
- data/spec/spec_helper.rb +136 -0
- data/tasks/ann.rake +83 -0
- data/tasks/constants.rb +118 -0
- data/tasks/gem.rake +196 -0
- data/tasks/git.rake +38 -0
- data/tasks/helpers.rb +130 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +35 -0
- data/tasks/rdoc.rake +46 -0
- data/tasks/rubyforge.rake +54 -0
- data/tasks/setup.rb +129 -0
- data/tasks/spec.rake +44 -0
- data/tasks/svn.rake +48 -0
- data/tasks/test.rake +41 -0
- metadata +122 -0
data/Changelog
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Copyright (c) 2011-2012 Jérémy Zurcher
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to
|
5
|
+
deal in the Software without restriction, including without limitation the
|
6
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
7
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
16
|
+
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
zorglub
|
2
|
+
by Jérémy Zurcher
|
3
|
+
http://cgit.asynk.ch/cgi-bin/cgit/zorglub
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
a nano web application framework based on rack[http://rack.rubyforge.org/]
|
8
|
+
|
9
|
+
== FEATURES:
|
10
|
+
|
11
|
+
* class#method mapping scheme (/class_mapping/method_name/*args)
|
12
|
+
* class level layout and engine specification
|
13
|
+
* method level layout, engine and view specification
|
14
|
+
* before_all and after_all methods callbacks
|
15
|
+
* redirection
|
16
|
+
* partial
|
17
|
+
* class level inherited variables
|
18
|
+
* session
|
19
|
+
|
20
|
+
== SYNOPSIS:
|
21
|
+
|
22
|
+
For a simple test application run:
|
23
|
+
* rackup ./example/sample.ru
|
24
|
+
|
25
|
+
Don't forget to look at
|
26
|
+
* the spec/ folder
|
27
|
+
|
28
|
+
== REQUIREMENTS:
|
29
|
+
|
30
|
+
* rack
|
31
|
+
|
32
|
+
== DOWNLOAD/INSTALL:
|
33
|
+
|
34
|
+
From rubygems:
|
35
|
+
|
36
|
+
[sudo] gem install zorglub
|
37
|
+
|
38
|
+
or from the git repository on github:
|
39
|
+
|
40
|
+
git clone git://github.com/jeremyz/zorglub.git
|
41
|
+
cd zorglub
|
42
|
+
rake gem:install
|
43
|
+
|
44
|
+
== RESOURCES:
|
45
|
+
|
46
|
+
You can find this project in a few places:
|
47
|
+
|
48
|
+
Online repositories:
|
49
|
+
|
50
|
+
* https://github.com/jeremyz/zorglub
|
51
|
+
* http://cgit.asynk.ch/cgi-bin/cgit/zorglub/
|
52
|
+
|
53
|
+
== LICENSE:
|
54
|
+
|
55
|
+
See MIT-LICENSE file.
|
data/Rakefile
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
2
|
+
#
|
3
|
+
require './lib/zorglub.rb'
|
4
|
+
load './tasks/setup.rb'
|
5
|
+
#
|
6
|
+
# Project general information
|
7
|
+
PROJ.name = 'zorglub'
|
8
|
+
PROJ.authors = 'Jérémy Zurcher'
|
9
|
+
PROJ.email = 'jeremy@asynk.ch'
|
10
|
+
PROJ.url = 'http://cgit.asynk.ch/cgi-bin/cgit/zorglub'
|
11
|
+
PROJ.version = Zorglub::VERSION
|
12
|
+
PROJ.rubyforge.name = 'FIXME'
|
13
|
+
PROJ.readme_file = 'README.rdoc'
|
14
|
+
#
|
15
|
+
# Annoucement
|
16
|
+
PROJ.ann.paragraphs << 'FEATURES' << 'SYNOPSIS' << 'REQUIREMENTS' << 'DOWNLOAD/INSTALL' << 'CREDITS' << 'LICENSE'
|
17
|
+
PROJ.ann.email[:from] = 'jeremy@asynk.ch'
|
18
|
+
PROJ.ann.email[:to] = ['FIXME']
|
19
|
+
PROJ.ann.email[:server] = 'FIXME'
|
20
|
+
PROJ.ann.email[:tls] = false
|
21
|
+
# Gem specifications
|
22
|
+
PROJ.gem.need_tar = false
|
23
|
+
PROJ.gem.files = %w(Changelog MIT-LICENSE README.rdoc Rakefile) + Dir.glob("{ext,lib,spec,tasks}/**/*[^~]").reject { |fn| test ?d, fn }
|
24
|
+
PROJ.gem.platform = Gem::Platform::RUBY
|
25
|
+
PROJ.gem.required_ruby_version = ">= 1.9.2"
|
26
|
+
#
|
27
|
+
# Override Mr. Bones autogenerated extensions and force ours in
|
28
|
+
#PROJ.gem.extras['extensions'] = %w(ext/extconf.rb)
|
29
|
+
#PROJ.gem.extras['required_ruby_version'] = ">= 1.9.2"
|
30
|
+
#
|
31
|
+
# RDoc
|
32
|
+
PROJ.rdoc.exclude << '^ext\/'
|
33
|
+
PROJ.rdoc.opts << '-x' << 'ext'
|
34
|
+
#
|
35
|
+
# Ruby
|
36
|
+
PROJ.ruby_opts = []
|
37
|
+
PROJ.ruby_opts << '-I' << 'lib'
|
38
|
+
#
|
39
|
+
# RSpec
|
40
|
+
PROJ.spec.files.exclude /rbx/
|
41
|
+
PROJ.spec.opts << '--color'
|
42
|
+
#
|
43
|
+
# Rcov
|
44
|
+
PROJ.rcov.opts << '-I lib'
|
45
|
+
#
|
46
|
+
# Dependencies
|
47
|
+
depend_on 'rack'
|
48
|
+
depend_on 'rake', '>=0.8.0'
|
49
|
+
#
|
50
|
+
task :default => [:spec]
|
51
|
+
#
|
52
|
+
desc "Build all packages"
|
53
|
+
task :package => 'gem:package'
|
54
|
+
#
|
55
|
+
desc "Install the gem locally"
|
56
|
+
task :install => 'gem:install'
|
57
|
+
#
|
58
|
+
# EOF
|
data/lib/zorglub/app.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
2
|
+
#
|
3
|
+
require 'rack'
|
4
|
+
#
|
5
|
+
module Zorglub
|
6
|
+
#
|
7
|
+
class App < Rack::URLMap
|
8
|
+
#
|
9
|
+
def initialize map={}, &block
|
10
|
+
super
|
11
|
+
@map = map
|
12
|
+
instance_eval &block if block_given?
|
13
|
+
remap @map
|
14
|
+
end
|
15
|
+
#
|
16
|
+
def map location, object
|
17
|
+
return unless location and object
|
18
|
+
raise Exception.new "#{@map[location]} already mapped to #{location}" if @map.has_key? location
|
19
|
+
object.app = self
|
20
|
+
@map.merge! location.to_s=>object
|
21
|
+
remap @map
|
22
|
+
end
|
23
|
+
#
|
24
|
+
def delete location
|
25
|
+
@map.delete location
|
26
|
+
remap @map
|
27
|
+
end
|
28
|
+
#
|
29
|
+
def at location
|
30
|
+
@map[location]
|
31
|
+
end
|
32
|
+
#
|
33
|
+
def to object
|
34
|
+
@map.invert[object]
|
35
|
+
end
|
36
|
+
#
|
37
|
+
def to_hash
|
38
|
+
@map.dup
|
39
|
+
end
|
40
|
+
#
|
41
|
+
end
|
42
|
+
#
|
43
|
+
end
|
44
|
+
#
|
45
|
+
# EOF
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
2
|
+
#
|
3
|
+
module Zorglub
|
4
|
+
#
|
5
|
+
class Config
|
6
|
+
@options = {
|
7
|
+
:root => '.',
|
8
|
+
:engine => nil,
|
9
|
+
:layout => 'default',
|
10
|
+
:view_dir => 'view',
|
11
|
+
:layout_dir => 'layout',
|
12
|
+
:session_on => false
|
13
|
+
}
|
14
|
+
@engines = { }
|
15
|
+
class << self
|
16
|
+
#
|
17
|
+
def [] k
|
18
|
+
@options[k]
|
19
|
+
end
|
20
|
+
#
|
21
|
+
def []= k, v
|
22
|
+
@options[k]=v
|
23
|
+
end
|
24
|
+
#
|
25
|
+
def view_base_path
|
26
|
+
p = @options[:view_path]
|
27
|
+
( p.nil? ? File.join(@options[:root], @options[:view_dir]) : p )
|
28
|
+
end
|
29
|
+
#
|
30
|
+
def layout_base_path
|
31
|
+
p = @options[:layout_path]
|
32
|
+
( p.nil? ? File.join(@options[:root], @options[:layout_dir]) : p )
|
33
|
+
end
|
34
|
+
#
|
35
|
+
def register_engine name, ext, proc
|
36
|
+
return unless name
|
37
|
+
@engines[name]=[ ext, proc ]
|
38
|
+
end
|
39
|
+
#
|
40
|
+
def engine_ext engine
|
41
|
+
e = @engines[engine]
|
42
|
+
return '' if e.nil?
|
43
|
+
x=e[0]
|
44
|
+
( x.nil? ? '' : '.'+x )
|
45
|
+
end
|
46
|
+
#
|
47
|
+
def engine_proc engine
|
48
|
+
e = @engines[engine]
|
49
|
+
( e.nil? ? nil : e[1] )
|
50
|
+
end
|
51
|
+
#
|
52
|
+
end
|
53
|
+
#
|
54
|
+
def self.method_missing m, *args, &block
|
55
|
+
if m=~/(.*)=$/
|
56
|
+
@options[$1.to_sym]=args[0]
|
57
|
+
else
|
58
|
+
@options[m.to_sym]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
#
|
62
|
+
end
|
63
|
+
#
|
64
|
+
end
|
65
|
+
#
|
66
|
+
# EOF
|
data/lib/zorglub/node.rb
ADDED
@@ -0,0 +1,196 @@
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
2
|
+
#
|
3
|
+
module Zorglub
|
4
|
+
#
|
5
|
+
class Node
|
6
|
+
#
|
7
|
+
@hooks = {
|
8
|
+
:before_all => [],
|
9
|
+
:after_all => [],
|
10
|
+
}
|
11
|
+
#
|
12
|
+
@inherited_vars = { }
|
13
|
+
#
|
14
|
+
class << self
|
15
|
+
#
|
16
|
+
attr_reader :hooks, :inherited_vars
|
17
|
+
#
|
18
|
+
def inherited sub
|
19
|
+
sub.layout layout
|
20
|
+
sub.engine engine
|
21
|
+
sub.instance_variable_set :@inherited_vars, {}
|
22
|
+
@inherited_vars.each do |s,v| sub.inherited_var s, *v end
|
23
|
+
end
|
24
|
+
#
|
25
|
+
def engine engine=nil
|
26
|
+
@engine = engine unless engine.nil? or engine.empty?
|
27
|
+
@engine ||= Config.engine
|
28
|
+
end
|
29
|
+
#
|
30
|
+
def layout layout=nil
|
31
|
+
@layout = layout unless layout.nil? or layout.empty?
|
32
|
+
@layout ||= Config.layout
|
33
|
+
end
|
34
|
+
#
|
35
|
+
def inherited_var sym, *args
|
36
|
+
var = @inherited_vars[sym] ||=[]
|
37
|
+
unless args.empty?
|
38
|
+
var.concat args
|
39
|
+
var.uniq!
|
40
|
+
end
|
41
|
+
var
|
42
|
+
end
|
43
|
+
#
|
44
|
+
attr_writer :app
|
45
|
+
def map app, location
|
46
|
+
@app = app
|
47
|
+
@app.map location, self
|
48
|
+
end
|
49
|
+
#
|
50
|
+
def r *args
|
51
|
+
@r ||= @app.to self
|
52
|
+
(args.empty? ? @r : File.join( @r, args.map { |x| x.to_s } ) )
|
53
|
+
end
|
54
|
+
#
|
55
|
+
def call env
|
56
|
+
meth, *args = env['PATH_INFO'].sub(/^\//,'').split '/'
|
57
|
+
meth||= 'index'
|
58
|
+
node = self.new env, {:engine=>engine,:layout=>layout,:view=>r(meth),:method=>meth,:args=>args}
|
59
|
+
return error_404 node if not node.respond_to? meth
|
60
|
+
node.realize!
|
61
|
+
end
|
62
|
+
#
|
63
|
+
def partial meth, *args
|
64
|
+
node = self.new nil, {:engine=>engine,:layout=>nil,:view=>r(meth),:method=>meth.to_s,:args=>args}
|
65
|
+
return error_404 node if not node.respond_to? meth
|
66
|
+
node.feed!
|
67
|
+
node.content
|
68
|
+
end
|
69
|
+
#
|
70
|
+
def call_before_hooks obj
|
71
|
+
Node.hooks[:before_all].each do |blk| blk.call obj end
|
72
|
+
end
|
73
|
+
#
|
74
|
+
def before_all &blk
|
75
|
+
Node.hooks[:before_all]<< blk
|
76
|
+
Node.hooks[:before_all].uniq!
|
77
|
+
end
|
78
|
+
#
|
79
|
+
def call_after_hooks obj
|
80
|
+
Node.hooks[:after_all].each do |blk| blk.call obj end
|
81
|
+
end
|
82
|
+
#
|
83
|
+
def after_all &blk
|
84
|
+
Node.hooks[:after_all]<< blk
|
85
|
+
Node.hooks[:after_all].uniq!
|
86
|
+
end
|
87
|
+
#
|
88
|
+
def error_404 node
|
89
|
+
resp = node.response
|
90
|
+
resp.status = 404
|
91
|
+
resp['Content-Type'] = 'text/plain'
|
92
|
+
resp.write "%s mapped at %p can't respond to : %p" % [ node.class.name, node.r, node.request.env['PATH_INFO'] ]
|
93
|
+
resp
|
94
|
+
end
|
95
|
+
#
|
96
|
+
end
|
97
|
+
#
|
98
|
+
attr_reader :action, :request, :response, :content
|
99
|
+
#
|
100
|
+
def initialize env, action
|
101
|
+
@env = env
|
102
|
+
@action = action
|
103
|
+
@request = Rack::Request.new env
|
104
|
+
@response = Rack::Response.new
|
105
|
+
end
|
106
|
+
#
|
107
|
+
def realize!
|
108
|
+
catch(:stop_realize) {
|
109
|
+
feed!
|
110
|
+
response.write @content
|
111
|
+
response.finish
|
112
|
+
response
|
113
|
+
}
|
114
|
+
end
|
115
|
+
#
|
116
|
+
def feed!
|
117
|
+
Node.call_before_hooks self
|
118
|
+
state :meth
|
119
|
+
@content = self.send @action[:method], *@action[:args]
|
120
|
+
v, l, e = view, layout, Config.engine_proc(@action[:engine])
|
121
|
+
# TODO compile and cache
|
122
|
+
state (@action[:layout].nil? ? :partial : :view)
|
123
|
+
@content = e.call v, self if e and File.exists? v
|
124
|
+
state :layout
|
125
|
+
@content = e.call l, self if e and File.exists? l
|
126
|
+
Node.call_after_hooks self
|
127
|
+
@content
|
128
|
+
end
|
129
|
+
#
|
130
|
+
def redirect target, options={}, &block
|
131
|
+
status = options[:status] || 302
|
132
|
+
body = options[:body] || redirect_body(target)
|
133
|
+
header = response.header.merge('Location' => target.to_s)
|
134
|
+
throw :stop_realize, Rack::Response.new(body, status, header, &block)
|
135
|
+
end
|
136
|
+
#
|
137
|
+
def redirect_body target
|
138
|
+
"You are being redirected, please follow this link to: <a href='#{target}'>#{target}</a>!"
|
139
|
+
end
|
140
|
+
#
|
141
|
+
def state state=nil
|
142
|
+
@action[:state] = state unless state.nil?
|
143
|
+
@action[:state]
|
144
|
+
end
|
145
|
+
#
|
146
|
+
def engine engine=nil
|
147
|
+
@action[:engine] = engine unless engine.nil? or engine.empty?
|
148
|
+
@action[:engine]
|
149
|
+
end
|
150
|
+
#
|
151
|
+
def layout layout=nil
|
152
|
+
@action[:layout] = layout unless layout.nil? or layout.empty?
|
153
|
+
return '' if @action[:layout].nil?
|
154
|
+
File.join(Config.layout_base_path, @action[:layout])+ Config.engine_ext(@action[:engine])
|
155
|
+
end
|
156
|
+
#
|
157
|
+
def no_layout
|
158
|
+
@action[:layout] = nil
|
159
|
+
end
|
160
|
+
#
|
161
|
+
def view view=nil
|
162
|
+
@action[:view] = view unless view.nil? or view.empty?
|
163
|
+
return '' if @action[:view].nil?
|
164
|
+
File.join(Config.view_base_path, @action[:view])+Config.engine_ext(@action[:engine])
|
165
|
+
end
|
166
|
+
#
|
167
|
+
def inherited_var sym, *args
|
168
|
+
d = self.class.inherited_vars[sym].clone || []
|
169
|
+
unless args.empty?
|
170
|
+
d.concat args
|
171
|
+
d.uniq!
|
172
|
+
end
|
173
|
+
d
|
174
|
+
end
|
175
|
+
#
|
176
|
+
def args
|
177
|
+
@action[:args]
|
178
|
+
end
|
179
|
+
#
|
180
|
+
def map
|
181
|
+
self.class.r
|
182
|
+
end
|
183
|
+
#
|
184
|
+
def r *args
|
185
|
+
File.join map, (args.empty? ? @action[:method] : args.map { |x| x.to_s } )
|
186
|
+
end
|
187
|
+
#
|
188
|
+
def html
|
189
|
+
[ :map, :r, :args, :engine, :layout, :view ].inject('') { |s,sym| s+="<p>#{sym} => #{self.send sym}</p>"; s }
|
190
|
+
end
|
191
|
+
#
|
192
|
+
end
|
193
|
+
#
|
194
|
+
end
|
195
|
+
#
|
196
|
+
# EOF
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
2
|
+
#
|
3
|
+
require 'securerandom'
|
4
|
+
#
|
5
|
+
module Zorglub
|
6
|
+
#
|
7
|
+
class Node
|
8
|
+
#
|
9
|
+
def session
|
10
|
+
@session ||= Session.new @request
|
11
|
+
end
|
12
|
+
end
|
13
|
+
#
|
14
|
+
class SessionHash
|
15
|
+
#
|
16
|
+
@data = {}
|
17
|
+
class << self
|
18
|
+
attr_reader :data
|
19
|
+
end
|
20
|
+
#
|
21
|
+
def initialize sid
|
22
|
+
@sid = sid
|
23
|
+
# TODO if sid is nil, one should be created
|
24
|
+
@session_data = SessionHash.data[sid]||={}
|
25
|
+
end
|
26
|
+
#
|
27
|
+
def exists?
|
28
|
+
not @sid.nil?
|
29
|
+
end
|
30
|
+
#
|
31
|
+
def [] idx
|
32
|
+
@session_data[idx]
|
33
|
+
end
|
34
|
+
#
|
35
|
+
def []= idx, v
|
36
|
+
@session_data[idx] = v
|
37
|
+
end
|
38
|
+
end
|
39
|
+
#
|
40
|
+
class Session
|
41
|
+
#
|
42
|
+
@session_key = 'zorglub.sid'
|
43
|
+
@session_kls = Zorglub::SessionHash
|
44
|
+
class << self
|
45
|
+
attr_accessor :session_key, :session_kls
|
46
|
+
end
|
47
|
+
#
|
48
|
+
def initialize req
|
49
|
+
@request = req
|
50
|
+
@instance = nil
|
51
|
+
end
|
52
|
+
#
|
53
|
+
def setup!
|
54
|
+
if Config.session_on
|
55
|
+
@instance = Session.session_kls.new @request.cookies[Session.session_key]
|
56
|
+
else
|
57
|
+
@instance = {}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
private :setup!
|
61
|
+
#
|
62
|
+
def exists?
|
63
|
+
setup! if @instance.nil?
|
64
|
+
@instance.exists?
|
65
|
+
end
|
66
|
+
#
|
67
|
+
def [] idx
|
68
|
+
setup! if @instance.nil?
|
69
|
+
@instance[idx]
|
70
|
+
end
|
71
|
+
#
|
72
|
+
def []= idx, v
|
73
|
+
setup! if @instance.nil?
|
74
|
+
@instance[idx] = v
|
75
|
+
end
|
76
|
+
#
|
77
|
+
end
|
78
|
+
#
|
79
|
+
end
|
80
|
+
#
|
81
|
+
# EOF
|
data/lib/zorglub.rb
ADDED
data/spec/app_spec.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
2
|
+
#
|
3
|
+
require 'spec_helper'
|
4
|
+
#
|
5
|
+
describe Zorglub do
|
6
|
+
#
|
7
|
+
describe Zorglub::App do
|
8
|
+
#
|
9
|
+
it "map should add a mapped node" do
|
10
|
+
APP.at("/temp").should be_nil
|
11
|
+
APP.map "/temp", Temp
|
12
|
+
APP.at("/temp").should be Temp
|
13
|
+
end
|
14
|
+
#
|
15
|
+
it "delete should delete a mapped node" do
|
16
|
+
APP.at("/temp").should be Temp
|
17
|
+
APP.delete "/temp"
|
18
|
+
APP.at("/temp").should be_nil
|
19
|
+
end
|
20
|
+
#
|
21
|
+
it "at should return mapped node" do
|
22
|
+
APP.at("/node1").should be Node1
|
23
|
+
end
|
24
|
+
#
|
25
|
+
it "at should return nil if no Node mapped" do
|
26
|
+
APP.at("/none").should be_nil
|
27
|
+
end
|
28
|
+
#
|
29
|
+
it "to should return path to node" do
|
30
|
+
APP.to(Node1).should == "/node1"
|
31
|
+
end
|
32
|
+
#
|
33
|
+
it "to should return nil if not an existing Node" do
|
34
|
+
APP.to(nil).should be_nil
|
35
|
+
end
|
36
|
+
#
|
37
|
+
it "to_hash should return a correct hash" do
|
38
|
+
APP.to_hash["/node1"].should be Node1
|
39
|
+
end
|
40
|
+
#
|
41
|
+
end
|
42
|
+
#
|
43
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|