innate 2009.04
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +2981 -0
- data/COPYING +18 -0
- data/MANIFEST +127 -0
- data/README.md +563 -0
- data/Rakefile +35 -0
- data/example/app/retro_games.rb +60 -0
- data/example/app/todo/layout/default.xhtml +11 -0
- data/example/app/todo/spec/todo.rb +63 -0
- data/example/app/todo/start.rb +51 -0
- data/example/app/todo/view/index.xhtml +39 -0
- data/example/app/whywiki_erb/layout/wiki.html.erb +15 -0
- data/example/app/whywiki_erb/spec/wiki.rb +19 -0
- data/example/app/whywiki_erb/start.rb +42 -0
- data/example/app/whywiki_erb/view/edit.erb +6 -0
- data/example/app/whywiki_erb/view/index.erb +12 -0
- data/example/custom_middleware.rb +35 -0
- data/example/hello.rb +11 -0
- data/example/howto_spec.rb +35 -0
- data/example/link.rb +27 -0
- data/example/provides.rb +31 -0
- data/example/session.rb +38 -0
- data/innate.gemspec +29 -0
- data/lib/innate.rb +269 -0
- data/lib/innate/action.rb +150 -0
- data/lib/innate/adapter.rb +76 -0
- data/lib/innate/cache.rb +134 -0
- data/lib/innate/cache/api.rb +128 -0
- data/lib/innate/cache/drb.rb +58 -0
- data/lib/innate/cache/file_based.rb +41 -0
- data/lib/innate/cache/marshal.rb +17 -0
- data/lib/innate/cache/memory.rb +22 -0
- data/lib/innate/cache/yaml.rb +17 -0
- data/lib/innate/current.rb +37 -0
- data/lib/innate/dynamap.rb +96 -0
- data/lib/innate/helper.rb +183 -0
- data/lib/innate/helper/aspect.rb +124 -0
- data/lib/innate/helper/cgi.rb +54 -0
- data/lib/innate/helper/flash.rb +36 -0
- data/lib/innate/helper/link.rb +94 -0
- data/lib/innate/helper/redirect.rb +85 -0
- data/lib/innate/helper/render.rb +87 -0
- data/lib/innate/helper/send_file.rb +26 -0
- data/lib/innate/log.rb +20 -0
- data/lib/innate/log/color_formatter.rb +43 -0
- data/lib/innate/log/hub.rb +73 -0
- data/lib/innate/middleware_compiler.rb +65 -0
- data/lib/innate/mock.rb +49 -0
- data/lib/innate/node.rb +1025 -0
- data/lib/innate/options.rb +37 -0
- data/lib/innate/options/dsl.rb +202 -0
- data/lib/innate/options/stub.rb +7 -0
- data/lib/innate/request.rb +141 -0
- data/lib/innate/response.rb +23 -0
- data/lib/innate/route.rb +110 -0
- data/lib/innate/session.rb +121 -0
- data/lib/innate/session/flash.rb +94 -0
- data/lib/innate/spec.rb +23 -0
- data/lib/innate/state.rb +27 -0
- data/lib/innate/state/accessor.rb +130 -0
- data/lib/innate/state/fiber.rb +74 -0
- data/lib/innate/state/thread.rb +47 -0
- data/lib/innate/traited.rb +85 -0
- data/lib/innate/trinity.rb +18 -0
- data/lib/innate/version.rb +3 -0
- data/lib/innate/view.rb +60 -0
- data/lib/innate/view/erb.rb +15 -0
- data/lib/innate/view/etanni.rb +36 -0
- data/lib/innate/view/none.rb +9 -0
- data/spec/example/app/retro_games.rb +30 -0
- data/spec/example/hello.rb +13 -0
- data/spec/example/link.rb +25 -0
- data/spec/example/provides.rb +16 -0
- data/spec/example/session.rb +22 -0
- data/spec/helper.rb +10 -0
- data/spec/innate/action/layout.rb +107 -0
- data/spec/innate/action/layout/file_layout.xhtml +1 -0
- data/spec/innate/cache/common.rb +47 -0
- data/spec/innate/cache/marshal.rb +5 -0
- data/spec/innate/cache/memory.rb +5 -0
- data/spec/innate/cache/yaml.rb +5 -0
- data/spec/innate/dynamap.rb +22 -0
- data/spec/innate/helper.rb +86 -0
- data/spec/innate/helper/aspect.rb +75 -0
- data/spec/innate/helper/cgi.rb +37 -0
- data/spec/innate/helper/flash.rb +118 -0
- data/spec/innate/helper/link.rb +139 -0
- data/spec/innate/helper/redirect.rb +160 -0
- data/spec/innate/helper/render.rb +133 -0
- data/spec/innate/helper/send_file.rb +21 -0
- data/spec/innate/helper/view/aspect_hello.xhtml +1 -0
- data/spec/innate/helper/view/locals.xhtml +1 -0
- data/spec/innate/helper/view/loop.xhtml +4 -0
- data/spec/innate/helper/view/num.xhtml +1 -0
- data/spec/innate/helper/view/partial.xhtml +1 -0
- data/spec/innate/helper/view/recursive.xhtml +7 -0
- data/spec/innate/mock.rb +84 -0
- data/spec/innate/node/mapping.rb +37 -0
- data/spec/innate/node/node.rb +134 -0
- data/spec/innate/node/resolve.rb +82 -0
- data/spec/innate/node/view/another_layout/another_layout.xhtml +3 -0
- data/spec/innate/node/view/bar.xhtml +1 -0
- data/spec/innate/node/view/foo.html.xhtml +1 -0
- data/spec/innate/node/view/only_view.xhtml +1 -0
- data/spec/innate/node/view/with_layout.xhtml +1 -0
- data/spec/innate/node/wrap_action_call.rb +83 -0
- data/spec/innate/options.rb +115 -0
- data/spec/innate/parameter.rb +154 -0
- data/spec/innate/provides.rb +99 -0
- data/spec/innate/provides/list.html.xhtml +1 -0
- data/spec/innate/provides/list.txt.xhtml +1 -0
- data/spec/innate/request.rb +77 -0
- data/spec/innate/route.rb +135 -0
- data/spec/innate/session.rb +54 -0
- data/spec/innate/state/fiber.rb +58 -0
- data/spec/innate/state/thread.rb +40 -0
- data/spec/innate/traited.rb +55 -0
- data/tasks/bacon.rake +66 -0
- data/tasks/changelog.rake +18 -0
- data/tasks/gem.rake +22 -0
- data/tasks/gem_installer.rake +76 -0
- data/tasks/grancher.rake +12 -0
- data/tasks/install_dependencies.rake +4 -0
- data/tasks/manifest.rake +4 -0
- data/tasks/rcov.rake +19 -0
- data/tasks/release.rake +51 -0
- data/tasks/reversion.rake +8 -0
- data/tasks/setup.rake +28 -0
- metadata +181 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
module Innate
|
4
|
+
module State
|
5
|
+
# In case fibers are not available we fall back to this wrapper.
|
6
|
+
#
|
7
|
+
# It will raise errors happening inside the wrapping Thread even if
|
8
|
+
# Thread::abort_on_exception is false.
|
9
|
+
#
|
10
|
+
# For things that require a mutex in a threaded environment, use
|
11
|
+
# STATE#sync, if Fiber is available no mutex will be used.
|
12
|
+
|
13
|
+
class Thread
|
14
|
+
SEMAPHORE = Mutex.new
|
15
|
+
|
16
|
+
def [](key)
|
17
|
+
::Thread.current[key]
|
18
|
+
end
|
19
|
+
|
20
|
+
def []=(key, value)
|
21
|
+
::Thread.current[key] = value
|
22
|
+
end
|
23
|
+
|
24
|
+
# Execute given block in a new Thread and rescue any exceptions before
|
25
|
+
# they reach Thread::new, so in case Thread::raise_on_exception is false
|
26
|
+
# we can still reraise the error outside of the Thread.
|
27
|
+
#
|
28
|
+
# This is not meant to be concurrent, we only use Thread as a wrapping
|
29
|
+
# context so we can store objects in Thread::current and access them from
|
30
|
+
# anywhere within this thread.
|
31
|
+
def wrap
|
32
|
+
value = ::Thread.new{ begin; yield; rescue Exception => ex; ex; end }.value
|
33
|
+
raise(value) if Exception === value
|
34
|
+
return value
|
35
|
+
end
|
36
|
+
|
37
|
+
def sync(&block)
|
38
|
+
SEMAPHORE.synchronize(&block)
|
39
|
+
end
|
40
|
+
|
41
|
+
def defer
|
42
|
+
a = ::Thread.current
|
43
|
+
::Thread.new{ b = ::Thread.current; a.keys.each{|k| b[k] = a[k] }; yield }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Innate
|
2
|
+
# Traited helps you doing configuration similar to class variables.
|
3
|
+
#
|
4
|
+
# It's built on a simple Hash, where keys are objects and the values the
|
5
|
+
# configuration.
|
6
|
+
# By using {Traited#ancestral_trait} you will get nicely inherited
|
7
|
+
# configuration, where keys later in the ancestors will take precedence.
|
8
|
+
#
|
9
|
+
# @example usage
|
10
|
+
#
|
11
|
+
# class Foo
|
12
|
+
# include Innate::Traited
|
13
|
+
# trait :hello => 'Hello'
|
14
|
+
#
|
15
|
+
# def initialize
|
16
|
+
# trait :hello => 'World!'
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# def show
|
20
|
+
# [class_trait[:hello], trait[:hello], ancestral_trait[:hello]]
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# Foo.trait[:hello] # => "Hello"
|
25
|
+
# foo = Foo.new
|
26
|
+
# foo.trait[:hello] # => "World!"
|
27
|
+
# foo.show # => ["Hello", "World!", "World!"]
|
28
|
+
module Traited
|
29
|
+
TRAITS = {}
|
30
|
+
|
31
|
+
def self.included(into)
|
32
|
+
into.extend(self)
|
33
|
+
end
|
34
|
+
|
35
|
+
def trait(hash = nil)
|
36
|
+
if hash
|
37
|
+
TRAITS[self] ||= {}
|
38
|
+
TRAITS[self].merge!(hash)
|
39
|
+
else
|
40
|
+
TRAITS[self] || {}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Builds a trait from all the ancestors, closer ancestors overwrite distant
|
45
|
+
# ancestors
|
46
|
+
#
|
47
|
+
# class Foo
|
48
|
+
# include Innate::Traited
|
49
|
+
# trait :one => :eins, :first => :erstes
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# class Bar < Foo
|
53
|
+
# trait :two => :zwei
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# class Foobar < Bar
|
57
|
+
# trait :three => :drei, :first => :overwritten
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
# Foobar.ancestral_trait
|
61
|
+
# # => {:three => :drei, :two => :zwei, :one => :eins, :first => :overwritten}
|
62
|
+
def ancestral_trait
|
63
|
+
result = {}
|
64
|
+
each_ancestral_trait{|trait| result.merge!(trait) }
|
65
|
+
result
|
66
|
+
end
|
67
|
+
|
68
|
+
def ancestral_trait_values(key)
|
69
|
+
result = []
|
70
|
+
each_ancestral_trait{|trait| result << trait[key] if trait.key?(key) }
|
71
|
+
result
|
72
|
+
end
|
73
|
+
|
74
|
+
def each_ancestral_trait
|
75
|
+
ancs = respond_to?(:ancestors) ? ancestors : self.class.ancestors
|
76
|
+
ancs.unshift(self)
|
77
|
+
ancs.reverse_each{|anc| yield(TRAITS[anc]) if TRAITS.key?(anc) }
|
78
|
+
end
|
79
|
+
|
80
|
+
# trait for self.class if we are an instance
|
81
|
+
def class_trait
|
82
|
+
respond_to?(:ancestors) ? trait : self.class.trait
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'innate/state/accessor'
|
2
|
+
require 'innate/request'
|
3
|
+
|
4
|
+
module Innate
|
5
|
+
# The module to be included into the Controller it basically just provides
|
6
|
+
# #request, #response and #session, each accessing Thread.current to
|
7
|
+
# retrieve the demanded object
|
8
|
+
|
9
|
+
module Trinity
|
10
|
+
extend StateAccessor
|
11
|
+
|
12
|
+
state_accessor :request, :response, :session, :actions
|
13
|
+
|
14
|
+
def action
|
15
|
+
actions.last
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/innate/view.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
module Innate
|
2
|
+
|
3
|
+
# This is a container module for wrappers of templating engines and handles
|
4
|
+
# lazy requiring of needed engines.
|
5
|
+
|
6
|
+
module View
|
7
|
+
ENGINE, TEMP = {}, {}
|
8
|
+
|
9
|
+
module_function
|
10
|
+
|
11
|
+
def exts_of(engine)
|
12
|
+
name = engine.to_s
|
13
|
+
ENGINE.reject{|k,v| v != name }.keys
|
14
|
+
end
|
15
|
+
|
16
|
+
# Try to obtain given engine by its registered name.
|
17
|
+
def get(engine)
|
18
|
+
if klass = TEMP[engine]
|
19
|
+
return klass
|
20
|
+
elsif klass = ENGINE[engine]
|
21
|
+
TEMP[engine] = obtain(klass)
|
22
|
+
else
|
23
|
+
TEMP[engine] = obtain(engine, View)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# We need to put this in a Mutex because simultanous calls for the same
|
28
|
+
# class will cause race conditions and one call may return the wrong class
|
29
|
+
# on the first request (before TEMP is set).
|
30
|
+
# No mutex is used in Fiber environment, see Innate::State and subclasses.
|
31
|
+
def obtain(klass, root = Object)
|
32
|
+
STATE.sync do
|
33
|
+
klass.to_s.scan(/\w+/){|part| root = root.const_get(part) }
|
34
|
+
root
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Register given templating engine wrapper and extensions for later usage.
|
39
|
+
#
|
40
|
+
# +name+ : the class name of the templating engine wrapper
|
41
|
+
# +exts+ : any number of arguments will be turned into strings via #to_s
|
42
|
+
# that indicate which filename-extensions the templates may have.
|
43
|
+
def register(klass, *exts)
|
44
|
+
exts.each do |ext|
|
45
|
+
ext = ext.to_s
|
46
|
+
engine = ENGINE[ext]
|
47
|
+
Log.warn("overwriting %p, was set to %p" % [ext, engine]) if engine
|
48
|
+
ENGINE[ext] = klass
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
autoload :None, 'innate/view/none'
|
53
|
+
autoload :ERB, 'innate/view/erb'
|
54
|
+
autoload :Etanni, 'innate/view/etanni'
|
55
|
+
|
56
|
+
register 'Innate::View::None', :css, :html, :htm
|
57
|
+
register 'Innate::View::ERB', :erb
|
58
|
+
register 'Innate::View::Etanni', :xhtml
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module Innate
|
4
|
+
module View
|
5
|
+
module ERB
|
6
|
+
def self.call(action, string)
|
7
|
+
erb = ::ERB.new(string.to_s, nil, '%<>')
|
8
|
+
erb.filename = (action.view || action.method).to_s
|
9
|
+
html = erb.result(action.binding)
|
10
|
+
|
11
|
+
return html, 'text/html'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Innate
|
2
|
+
module View
|
3
|
+
module Etanni
|
4
|
+
def self.call(action, string)
|
5
|
+
template = Innate::Etanni.new(string.to_s)
|
6
|
+
html = template.result(action.binding, (action.view || action.method))
|
7
|
+
return html, 'text/html'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Etanni
|
13
|
+
def initialize(template)
|
14
|
+
@template = template
|
15
|
+
compile
|
16
|
+
end
|
17
|
+
|
18
|
+
def compile
|
19
|
+
temp = @template.dup
|
20
|
+
start_heredoc = "T" << Digest::SHA1.hexdigest(temp)
|
21
|
+
start_heredoc, end_heredoc = "\n<<#{start_heredoc}.chomp\n", "\n#{start_heredoc}\n"
|
22
|
+
bufadd = "_out_ << "
|
23
|
+
|
24
|
+
temp.gsub!(/<\?r\s+(.*?)\s+\?>/m,
|
25
|
+
"#{end_heredoc} \\1; #{bufadd} #{start_heredoc}")
|
26
|
+
|
27
|
+
@compiled = "_out_ = ''
|
28
|
+
#{bufadd} #{start_heredoc} #{temp} #{end_heredoc}
|
29
|
+
_out_"
|
30
|
+
end
|
31
|
+
|
32
|
+
def result(binding, filename = '<Etanni>')
|
33
|
+
eval(@compiled, binding, filename).to_s.strip
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec/helper'
|
2
|
+
require 'example/app/retro_games'
|
3
|
+
|
4
|
+
describe 'Retro-games app' do
|
5
|
+
behaves_like :mock
|
6
|
+
|
7
|
+
it 'lists the first game' do
|
8
|
+
get '/'
|
9
|
+
last_response.should =~ /1 => Pacman/
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'has a form to add another game' do
|
13
|
+
get '/'
|
14
|
+
last_response.should =~ /<form/
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'allows you to add another game' do
|
18
|
+
post '/create', :name => 'Street Fighter II'
|
19
|
+
follow_redirect!
|
20
|
+
last_response.should =~ /0 => Street Fighter II/
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'allows you to vote for a game' do
|
24
|
+
get '/vote/Street+Fighter+II'
|
25
|
+
follow_redirect!
|
26
|
+
last_response.should =~ /1 => Street Fighter II/
|
27
|
+
end
|
28
|
+
|
29
|
+
FileUtils.rm_f('games.yaml')
|
30
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec/helper'
|
2
|
+
require 'example/hello'
|
3
|
+
|
4
|
+
describe 'example/hello' do
|
5
|
+
behaves_like :mock
|
6
|
+
|
7
|
+
should 'have index action' do
|
8
|
+
got = get('/')
|
9
|
+
got.status.should == 200
|
10
|
+
got['Content-Type'].should == 'text/html'
|
11
|
+
got.body.should == 'Hello, World!'
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec/helper'
|
2
|
+
require 'example/link'
|
3
|
+
|
4
|
+
describe 'example/link' do
|
5
|
+
behaves_like :mock
|
6
|
+
|
7
|
+
should 'have index on Linking' do
|
8
|
+
get('/').body.should == 'Index links to <a href="/help">Help?</a>'
|
9
|
+
end
|
10
|
+
|
11
|
+
should 'have help on Linking' do
|
12
|
+
get('/help').body.should ==
|
13
|
+
"Help links to <a href=\"/link_to/another\">A Different Node</a>"
|
14
|
+
end
|
15
|
+
|
16
|
+
should 'have another on Different' do
|
17
|
+
get('/link_to/another').body.
|
18
|
+
should == "<a href=\"/link_to/and/deeper\">Another links even deeper</a>"
|
19
|
+
end
|
20
|
+
|
21
|
+
should 'have and__deeper on Different' do
|
22
|
+
get('/link_to/and/deeper').body.
|
23
|
+
should == "<a href=\"/index\">Back to Linking Node</a>"
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec/helper'
|
2
|
+
require 'example/provides'
|
3
|
+
|
4
|
+
describe 'examples/provide' do
|
5
|
+
behaves_like :mock
|
6
|
+
|
7
|
+
it 'provides YAML representation' do
|
8
|
+
get '/list.yaml'
|
9
|
+
last_response.body.should == ARTICLES.to_yaml
|
10
|
+
last_response['Content-Type'].should == 'text/yaml'
|
11
|
+
|
12
|
+
get '/list'
|
13
|
+
last_response.body.should == ''
|
14
|
+
last_response['Content-Type'].should == 'text/html'
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec/helper'
|
2
|
+
require 'example/session'
|
3
|
+
|
4
|
+
describe 'example/session' do
|
5
|
+
behaves_like :mock
|
6
|
+
|
7
|
+
it 'starts at 0' do
|
8
|
+
get('/').body.should =~ /Value is: 0/
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'increments the counter' do
|
12
|
+
get('/increment').body.should =~ /Value is: 1/
|
13
|
+
get('/increment').body.should =~ /Value is: 2/
|
14
|
+
get('/increment').body.should =~ /Value is: 3/
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'decrements the counter' do
|
18
|
+
get('/decrement').body.should =~ /Value is: 2/
|
19
|
+
get('/decrement').body.should =~ /Value is: 1/
|
20
|
+
get('/decrement').body.should =~ /Value is: 0/
|
21
|
+
end
|
22
|
+
end
|
data/spec/helper.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
if caller_line = caller.grep(%r!spec/innate/!).first
|
2
|
+
caller_file = caller_line.split(':', 2).first
|
3
|
+
caller_root = File.dirname(caller_file)
|
4
|
+
$0 = caller_file
|
5
|
+
end
|
6
|
+
|
7
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../lib/innate'))
|
8
|
+
require 'innate/spec'
|
9
|
+
|
10
|
+
Innate.options.roots = [caller_root] if caller_root
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# Copyright (c) 2009 Michael Fellinger m.fellinger@gmail.com
|
2
|
+
# All files in this distribution are subject to the terms of the Ruby license.
|
3
|
+
|
4
|
+
require 'spec/helper'
|
5
|
+
|
6
|
+
class SpecActionLayout
|
7
|
+
include Innate::Node
|
8
|
+
map_layouts '/'
|
9
|
+
end
|
10
|
+
|
11
|
+
class SpecActionLayoutMethod < SpecActionLayout
|
12
|
+
Innate.node('/from_method', self)
|
13
|
+
layout('method_layout')
|
14
|
+
|
15
|
+
def method_layout
|
16
|
+
'<pre>#{ @content }</pre>'
|
17
|
+
end
|
18
|
+
|
19
|
+
def index
|
20
|
+
'Method Layout'
|
21
|
+
end
|
22
|
+
|
23
|
+
def foo
|
24
|
+
"bar"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class SpecActionLayoutFile < SpecActionLayout
|
29
|
+
Innate.node('/from_file', self)
|
30
|
+
layout('file_layout')
|
31
|
+
|
32
|
+
def index
|
33
|
+
"File Layout"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class SpecActionLayoutSpecific < SpecActionLayout
|
38
|
+
Innate.node('/specific', self)
|
39
|
+
layout('file_layout'){|name, wish| name == 'index' }
|
40
|
+
|
41
|
+
def index
|
42
|
+
'Specific Layout'
|
43
|
+
end
|
44
|
+
|
45
|
+
def without
|
46
|
+
"Without wrapper"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class SpecActionLayoutDeny < SpecActionLayout
|
51
|
+
Innate.node('/deny', self)
|
52
|
+
layout('file_layout'){|name, wish| name != 'without' }
|
53
|
+
|
54
|
+
def index
|
55
|
+
"Deny Layout"
|
56
|
+
end
|
57
|
+
|
58
|
+
def without
|
59
|
+
"Without wrapper"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class SpecActionLayoutMulti < SpecActionLayout
|
64
|
+
Innate.node('/multi', self)
|
65
|
+
layout('file_layout'){|name, wish| name =~ /index|second/ }
|
66
|
+
|
67
|
+
def index
|
68
|
+
"Multi Layout Index"
|
69
|
+
end
|
70
|
+
|
71
|
+
def second
|
72
|
+
"Multi Layout Second"
|
73
|
+
end
|
74
|
+
|
75
|
+
def without
|
76
|
+
"Without wrapper"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe 'Innate::Action#layout' do
|
81
|
+
behaves_like :mock
|
82
|
+
|
83
|
+
it 'uses a layout method' do
|
84
|
+
get('/from_method').body.should == '<pre>Method Layout</pre>'
|
85
|
+
get('/from_method/foo').body.should == '<pre>bar</pre>'
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'uses a layout file' do
|
89
|
+
get('/from_file').body.strip.should == '<p>File Layout</p>'
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'denies layout to some actions' do
|
93
|
+
get('/deny').body.strip.should == '<p>Deny Layout</p>'
|
94
|
+
get('/deny/without').body.strip.should == 'Without wrapper'
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'uses layout only for specific action' do
|
98
|
+
get('/specific').body.strip.should == '<p>Specific Layout</p>'
|
99
|
+
get('/specific/without').body.strip.should == 'Without wrapper'
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'uses layout only for specific actions' do
|
103
|
+
get('/multi').body.strip.should == '<p>Multi Layout Index</p>'
|
104
|
+
get('/multi/second').body.strip.should == '<p>Multi Layout Second</p>'
|
105
|
+
get('/multi/without').body.strip.should == 'Without wrapper'
|
106
|
+
end
|
107
|
+
end
|