innate 2009.04
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|