manveru-innate 2009.02.06

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. data/CHANGELOG +1409 -0
  2. data/COPYING +18 -0
  3. data/MANIFEST +100 -0
  4. data/README.md +485 -0
  5. data/Rakefile +139 -0
  6. data/example/app/retro_games.rb +57 -0
  7. data/example/app/whywiki_erb/layout/wiki.html.erb +15 -0
  8. data/example/app/whywiki_erb/spec/wiki.rb +19 -0
  9. data/example/app/whywiki_erb/start.rb +45 -0
  10. data/example/app/whywiki_erb/view/edit.html.erb +6 -0
  11. data/example/app/whywiki_erb/view/index.html.erb +10 -0
  12. data/example/custom_middleware.rb +43 -0
  13. data/example/error_handling.rb +31 -0
  14. data/example/hello.rb +12 -0
  15. data/example/howto_spec.rb +60 -0
  16. data/example/link.rb +35 -0
  17. data/example/providing_hash.rb +46 -0
  18. data/example/session.rb +42 -0
  19. data/innate.gemspec +118 -0
  20. data/lib/innate.rb +191 -0
  21. data/lib/innate/action.rb +156 -0
  22. data/lib/innate/adapter.rb +89 -0
  23. data/lib/innate/cache.rb +117 -0
  24. data/lib/innate/cache/api.rb +106 -0
  25. data/lib/innate/cache/drb.rb +58 -0
  26. data/lib/innate/cache/file_based.rb +39 -0
  27. data/lib/innate/cache/marshal.rb +17 -0
  28. data/lib/innate/cache/memory.rb +22 -0
  29. data/lib/innate/cache/yaml.rb +17 -0
  30. data/lib/innate/core_compatibility/basic_object.rb +9 -0
  31. data/lib/innate/core_compatibility/string.rb +3 -0
  32. data/lib/innate/current.rb +37 -0
  33. data/lib/innate/dynamap.rb +81 -0
  34. data/lib/innate/helper.rb +195 -0
  35. data/lib/innate/helper/aspect.rb +62 -0
  36. data/lib/innate/helper/cgi.rb +39 -0
  37. data/lib/innate/helper/flash.rb +36 -0
  38. data/lib/innate/helper/link.rb +55 -0
  39. data/lib/innate/helper/partial.rb +90 -0
  40. data/lib/innate/helper/redirect.rb +85 -0
  41. data/lib/innate/helper/send_file.rb +18 -0
  42. data/lib/innate/log.rb +23 -0
  43. data/lib/innate/log/color_formatter.rb +43 -0
  44. data/lib/innate/log/hub.rb +72 -0
  45. data/lib/innate/mock.rb +49 -0
  46. data/lib/innate/node.rb +471 -0
  47. data/lib/innate/options.rb +91 -0
  48. data/lib/innate/options/dsl.rb +155 -0
  49. data/lib/innate/request.rb +165 -0
  50. data/lib/innate/response.rb +18 -0
  51. data/lib/innate/route.rb +109 -0
  52. data/lib/innate/session.rb +104 -0
  53. data/lib/innate/session/flash.rb +94 -0
  54. data/lib/innate/setup.rb +23 -0
  55. data/lib/innate/spec.rb +42 -0
  56. data/lib/innate/state.rb +22 -0
  57. data/lib/innate/state/accessor.rb +130 -0
  58. data/lib/innate/state/fiber.rb +68 -0
  59. data/lib/innate/state/thread.rb +39 -0
  60. data/lib/innate/traited.rb +20 -0
  61. data/lib/innate/trinity.rb +22 -0
  62. data/lib/innate/version.rb +3 -0
  63. data/lib/innate/view.rb +67 -0
  64. data/lib/innate/view/erb.rb +17 -0
  65. data/lib/innate/view/none.rb +9 -0
  66. data/lib/rack/middleware_compiler.rb +62 -0
  67. data/lib/rack/reloader.rb +192 -0
  68. data/spec/example/hello.rb +14 -0
  69. data/spec/example/link.rb +29 -0
  70. data/spec/helper.rb +2 -0
  71. data/spec/innate/cache/common.rb +45 -0
  72. data/spec/innate/cache/marshal.rb +5 -0
  73. data/spec/innate/cache/memory.rb +5 -0
  74. data/spec/innate/cache/yaml.rb +5 -0
  75. data/spec/innate/dynamap.rb +22 -0
  76. data/spec/innate/helper.rb +66 -0
  77. data/spec/innate/helper/aspect.rb +80 -0
  78. data/spec/innate/helper/cgi.rb +37 -0
  79. data/spec/innate/helper/flash.rb +148 -0
  80. data/spec/innate/helper/link.rb +82 -0
  81. data/spec/innate/helper/partial.rb +66 -0
  82. data/spec/innate/helper/redirect.rb +148 -0
  83. data/spec/innate/helper/send_file.rb +21 -0
  84. data/spec/innate/helper/view/aspect_hello.erb +1 -0
  85. data/spec/innate/helper/view/locals.erb +1 -0
  86. data/spec/innate/helper/view/loop.erb +4 -0
  87. data/spec/innate/helper/view/num.erb +1 -0
  88. data/spec/innate/helper/view/partial.erb +1 -0
  89. data/spec/innate/helper/view/recursive.erb +8 -0
  90. data/spec/innate/mock.rb +84 -0
  91. data/spec/innate/node.rb +180 -0
  92. data/spec/innate/node/bar.html +1 -0
  93. data/spec/innate/node/foo.html.erb +1 -0
  94. data/spec/innate/node/with_layout.erb +3 -0
  95. data/spec/innate/options.rb +90 -0
  96. data/spec/innate/parameter.rb +154 -0
  97. data/spec/innate/request.rb +73 -0
  98. data/spec/innate/route.rb +129 -0
  99. data/spec/innate/session.rb +59 -0
  100. data/spec/innate/traited.rb +55 -0
  101. metadata +160 -0
data/example/link.rb ADDED
@@ -0,0 +1,35 @@
1
+ require 'innate'
2
+
3
+ class Linking
4
+ include Innate::Node
5
+ map '/'
6
+
7
+ def index
8
+ "simple link<br />" +
9
+ a('Help?', :help)
10
+ end
11
+
12
+ def new
13
+ "Something new!"
14
+ end
15
+
16
+ def help
17
+ "You have help<br />" +
18
+ Different.a('A Different Node', :another)
19
+ end
20
+ end
21
+
22
+ class Different
23
+ include Innate::Node
24
+ map '/link_to'
25
+
26
+ def another
27
+ a('Even deeper', 'and/deeper')
28
+ end
29
+
30
+ def and__deeper
31
+ Linking.a('Back to Linking Node', :index)
32
+ end
33
+ end
34
+
35
+ Innate.start
@@ -0,0 +1,46 @@
1
+ require 'innate'
2
+
3
+ # This demonstrates how to obtain different content types from the return value
4
+ # of action methods.
5
+ #
6
+ # Try following requests:
7
+ # /set/foo/bar
8
+ # /set/duh/duf
9
+ #
10
+ # /index.json
11
+ # /index.yaml
12
+ #
13
+ # /get/foo.json
14
+ # /get/foo.yaml
15
+ #
16
+ # Note that this functionality is quite experimental, but by strategically
17
+ # placing ressources in actions it may be possible to achieve interesting
18
+ # effects and interoperability with JavaScript at a low cost.
19
+ #
20
+ # TODO:
21
+ # * parsing requests based on the content-type, but that's much less
22
+ # straight-forward and would require some kind of convention?
23
+
24
+ class Dict
25
+ include Innate::Node
26
+ map '/'
27
+
28
+ DICT = {}
29
+
30
+ # /get/foo || /get/foo.json || /get/foo.yaml
31
+ def get(key)
32
+ {key => DICT[key]}
33
+ end
34
+
35
+ # /set/foo/bar || /set/foo/bar.json || /set/foo/bar.yaml
36
+ def set(key, value)
37
+ {key => (DICT[key] = value)}
38
+ end
39
+
40
+ # /index.json || /.json || /index.yaml || /.yaml
41
+ def index
42
+ DICT
43
+ end
44
+ end
45
+
46
+ Innate.start
@@ -0,0 +1,42 @@
1
+ require 'innate'
2
+
3
+ class Hello
4
+ include Innate::Node
5
+ map '/'
6
+
7
+ helper :link, :cgi
8
+
9
+ provide :html => :haml
10
+
11
+ TEMPLATE = '
12
+ !!! XML
13
+ !!!
14
+ %html
15
+ %head
16
+ %title Session example
17
+ %body
18
+ %h1 Session example
19
+ = "Value is #{session[:value]}"
20
+ %br/
21
+ = a :increment
22
+ %br/
23
+ = a :decrement
24
+ '.strip
25
+
26
+ def index
27
+ session[:value] = 0
28
+ TEMPLATE
29
+ end
30
+
31
+ def increment
32
+ session[:value] += 1 if session[:value]
33
+ TEMPLATE
34
+ end
35
+
36
+ def decrement
37
+ session[:value] -= 1 if session[:value]
38
+ TEMPLATE
39
+ end
40
+ end
41
+
42
+ Innate.start
data/innate.gemspec ADDED
@@ -0,0 +1,118 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "innate"
3
+ s.version = "2009.02.06"
4
+
5
+ s.summary = "Powerful web-framework wrapper for Rack."
6
+ s.description = "Simple, straight-forward, base for web-frameworks."
7
+ s.platform = "ruby"
8
+ s.has_rdoc = true
9
+ s.author = "Michael 'manveru' Fellinger"
10
+ s.email = "m.fellinger@gmail.com"
11
+ s.homepage = "http://github.com/manveru/innate"
12
+ s.require_path = "lib"
13
+
14
+ s.add_dependency('rack', '>= 0.4.0')
15
+
16
+ s.files = [
17
+ "CHANGELOG",
18
+ "COPYING",
19
+ "MANIFEST",
20
+ "README.md",
21
+ "Rakefile",
22
+ "example/app/retro_games.rb",
23
+ "example/app/whywiki_erb/layout/wiki.html.erb",
24
+ "example/app/whywiki_erb/spec/wiki.rb",
25
+ "example/app/whywiki_erb/start.rb",
26
+ "example/app/whywiki_erb/view/edit.html.erb",
27
+ "example/app/whywiki_erb/view/index.html.erb",
28
+ "example/custom_middleware.rb",
29
+ "example/error_handling.rb",
30
+ "example/hello.rb",
31
+ "example/howto_spec.rb",
32
+ "example/link.rb",
33
+ "example/providing_hash.rb",
34
+ "example/session.rb",
35
+ "innate.gemspec",
36
+ "lib/innate.rb",
37
+ "lib/innate/action.rb",
38
+ "lib/innate/adapter.rb",
39
+ "lib/innate/cache.rb",
40
+ "lib/innate/cache/api.rb",
41
+ "lib/innate/cache/drb.rb",
42
+ "lib/innate/cache/file_based.rb",
43
+ "lib/innate/cache/marshal.rb",
44
+ "lib/innate/cache/memory.rb",
45
+ "lib/innate/cache/yaml.rb",
46
+ "lib/innate/core_compatibility/basic_object.rb",
47
+ "lib/innate/core_compatibility/string.rb",
48
+ "lib/innate/current.rb",
49
+ "lib/innate/dynamap.rb",
50
+ "lib/innate/helper.rb",
51
+ "lib/innate/helper/aspect.rb",
52
+ "lib/innate/helper/cgi.rb",
53
+ "lib/innate/helper/flash.rb",
54
+ "lib/innate/helper/link.rb",
55
+ "lib/innate/helper/partial.rb",
56
+ "lib/innate/helper/redirect.rb",
57
+ "lib/innate/helper/send_file.rb",
58
+ "lib/innate/log.rb",
59
+ "lib/innate/log/color_formatter.rb",
60
+ "lib/innate/log/hub.rb",
61
+ "lib/innate/mock.rb",
62
+ "lib/innate/node.rb",
63
+ "lib/innate/options.rb",
64
+ "lib/innate/options/dsl.rb",
65
+ "lib/innate/request.rb",
66
+ "lib/innate/response.rb",
67
+ "lib/innate/route.rb",
68
+ "lib/innate/session.rb",
69
+ "lib/innate/session/flash.rb",
70
+ "lib/innate/setup.rb",
71
+ "lib/innate/spec.rb",
72
+ "lib/innate/state.rb",
73
+ "lib/innate/state/accessor.rb",
74
+ "lib/innate/state/fiber.rb",
75
+ "lib/innate/state/thread.rb",
76
+ "lib/innate/traited.rb",
77
+ "lib/innate/trinity.rb",
78
+ "lib/innate/version.rb",
79
+ "lib/innate/view.rb",
80
+ "lib/innate/view/erb.rb",
81
+ "lib/innate/view/none.rb",
82
+ "lib/rack/middleware_compiler.rb",
83
+ "lib/rack/reloader.rb",
84
+ "spec/example/hello.rb",
85
+ "spec/example/link.rb",
86
+ "spec/helper.rb",
87
+ "spec/innate/cache/common.rb",
88
+ "spec/innate/cache/marshal.rb",
89
+ "spec/innate/cache/memory.rb",
90
+ "spec/innate/cache/yaml.rb",
91
+ "spec/innate/dynamap.rb",
92
+ "spec/innate/helper.rb",
93
+ "spec/innate/helper/aspect.rb",
94
+ "spec/innate/helper/cgi.rb",
95
+ "spec/innate/helper/flash.rb",
96
+ "spec/innate/helper/link.rb",
97
+ "spec/innate/helper/partial.rb",
98
+ "spec/innate/helper/redirect.rb",
99
+ "spec/innate/helper/send_file.rb",
100
+ "spec/innate/helper/view/aspect_hello.erb",
101
+ "spec/innate/helper/view/locals.erb",
102
+ "spec/innate/helper/view/loop.erb",
103
+ "spec/innate/helper/view/num.erb",
104
+ "spec/innate/helper/view/partial.erb",
105
+ "spec/innate/helper/view/recursive.erb",
106
+ "spec/innate/mock.rb",
107
+ "spec/innate/node.rb",
108
+ "spec/innate/node/bar.html",
109
+ "spec/innate/node/foo.html.erb",
110
+ "spec/innate/node/with_layout.erb",
111
+ "spec/innate/options.rb",
112
+ "spec/innate/parameter.rb",
113
+ "spec/innate/request.rb",
114
+ "spec/innate/route.rb",
115
+ "spec/innate/session.rb",
116
+ "spec/innate/traited.rb"
117
+ ]
118
+ end
data/lib/innate.rb ADDED
@@ -0,0 +1,191 @@
1
+ # What can be done with fewer assumptions is done in vain with more.
2
+ # -- William of Ockham (ca. 1285-1349)
3
+ #
4
+ # Name-space of Innate, just about everything goes in here.
5
+ #
6
+ # Exceptions are:
7
+ #
8
+ # * Logger::ColorFormatter
9
+ # * In 1.8, we define ::BasicObject
10
+ # * In 1.9, we define ::String#each
11
+ #
12
+ module Innate
13
+ ROOT = File.expand_path(File.dirname(__FILE__))
14
+
15
+ unless $LOAD_PATH.any?{|lp| File.expand_path(lp) == ROOT }
16
+ $LOAD_PATH.unshift(ROOT)
17
+ end
18
+ end
19
+
20
+ # stdlib
21
+ require 'pp'
22
+ require 'set'
23
+ require 'pathname'
24
+ require 'digest/sha1'
25
+ require 'ipaddr'
26
+ require 'socket'
27
+ require 'logger'
28
+ require 'uri'
29
+
30
+ # 3rd party
31
+ require 'rack'
32
+
33
+ # innate core patches
34
+ require 'innate/core_compatibility/string'
35
+ require 'innate/core_compatibility/basic_object'
36
+
37
+ # innate core
38
+ require 'innate/version'
39
+ require 'innate/traited'
40
+ require 'innate/cache'
41
+ require 'innate/node'
42
+ require 'innate/options'
43
+ require 'innate/log'
44
+ require 'innate/state'
45
+ require 'innate/trinity'
46
+ require 'innate/current'
47
+ require 'innate/mock'
48
+ require 'innate/adapter'
49
+ require 'innate/action'
50
+ require 'innate/helper'
51
+ require 'innate/view'
52
+ require 'innate/session'
53
+ require 'innate/session/flash'
54
+ require 'innate/dynamap'
55
+ require 'innate/route'
56
+
57
+ require 'rack/reloader'
58
+ require 'rack/middleware_compiler'
59
+
60
+ module Innate
61
+ extend Trinity
62
+
63
+ # Note that `m.innate` takes away most of the boring part and leaves it up to
64
+ # you to select your middleware in your application.
65
+ #
66
+ # This expands to:
67
+ #
68
+ # use Rack::ShowExceptions
69
+ # use Rack::RouteExceptions
70
+ # use Rack::ShowStatus
71
+ # use Rack::Reloader
72
+ # use Rack::Cascade.new([
73
+ # Rack::File.new('public'),
74
+ # Innate::Current.new(
75
+ # Rack::Cascade.new([
76
+ # Innate::Rewrite.new(Innate::DynaMap),
77
+ # Innate::Route.new(Innate::DynaMap)])))
78
+ DEFAULT_MIDDLEWARE = lambda{|m|
79
+ m.use Rack::CommonLogger # usually fast, depending on the output
80
+ m.use Rack::ShowExceptions # fast
81
+ # m.use Rack::RouteExceptions # fast, use when you have custom error pages.
82
+ m.use Rack::ShowStatus # fast
83
+ m.use Rack::Reloader # reasonably fast depending on settings
84
+ # m.use Rack::Lint # slow, use only while developing
85
+
86
+ m.innate
87
+ }
88
+
89
+ module_function
90
+
91
+ def start(parameter = {}, &block)
92
+ setup_dependencies
93
+ setup_middleware(&block)
94
+
95
+ options[:app][:root] = go_figure_root(parameter, caller)
96
+ parameter.reject!{|k, v| [:root, :file].include?(k) }
97
+ options.merge!(parameter)
98
+
99
+ return if options.started
100
+ options.started = true
101
+
102
+ trap(options[:trap]){ stop(10) } if options[:trap]
103
+
104
+ start!(options)
105
+ end
106
+
107
+ def start!(options = Innate.options)
108
+ Adapter.start(middleware(:innate), options)
109
+ end
110
+
111
+ def stop(wait = 3)
112
+ Log.info("Shutdown Innate within #{wait} seconds")
113
+ Timeout.timeout(wait){ exit }
114
+ ensure
115
+ exit!
116
+ end
117
+
118
+ def middleware(name, &block)
119
+ Rack::MiddlewareCompiler.build(name, &block)
120
+ end
121
+
122
+ def middleware!(name, &block)
123
+ Rack::MiddlewareCompiler.build!(name, &block)
124
+ end
125
+
126
+ def setup_dependencies
127
+ options[:setup].each{|obj| obj.setup }
128
+ end
129
+
130
+ # Set the default middleware for applications.
131
+ def setup_middleware(&block)
132
+ middleware(:innate, &(block || DEFAULT_MIDDLEWARE))
133
+ end
134
+
135
+ # Pass the +env+ to this method and it will be sent to the appropriate
136
+ # middleware called +mw+.
137
+ # Tries to avoid recursion.
138
+
139
+ def call(env, mw = :innate)
140
+ this_file = File.expand_path(__FILE__)
141
+ count = 0
142
+ caller_lines(caller){|f, l, m| count += 1 if f == this_file }
143
+
144
+ raise RuntimeError, "Recursive loop in Innate::call" if count > 10
145
+
146
+ middleware(mw).call(env)
147
+ end
148
+
149
+ # Innate can be started by:
150
+ #
151
+ # Innate.start :file => __FILE__
152
+ # Innate.start :root => '/path/to/here'
153
+ #
154
+ # In case these options are not passed we will try to figure out a file named
155
+ # `start.rb` in the backtrace and use the directory it resides in.
156
+ #
157
+ # TODO: better documentation and nice defaults, don't want to rely on a
158
+ # filename, bad mojo.
159
+
160
+ def go_figure_root(options, backtrace)
161
+ if o_file = options[:file]
162
+ return File.dirname(o_file)
163
+ elsif root = options[:root]
164
+ return root
165
+ end
166
+
167
+ pwd = Dir.pwd
168
+
169
+ return pwd if File.file?(File.join(pwd, 'start.rb'))
170
+
171
+ caller_lines(backtrace) do |file, line, method|
172
+ dir, file = File.split(File.expand_path(file))
173
+ return dir if file == "start.rb"
174
+ end
175
+
176
+ return nil
177
+ end
178
+
179
+ # yields +file+, +line+, +method+
180
+ def caller_lines(backtrace)
181
+ backtrace.each do |line|
182
+ if line =~ /^(.*?):(\d+):in `(.*)'$/
183
+ file, line, method = $1, $2.to_i, $3
184
+ elsif line =~ /^(.*?):(\d+)$/
185
+ file, line, method = $1, $2.to_i, nil
186
+ end
187
+
188
+ yield(File.expand_path(file), line, method) if file and File.file?(file)
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,156 @@
1
+ module Innate
2
+ ACTION_MEMBERS = [ :node, :method, :params, :view, :layout, :instance, :exts,
3
+ :wish, :options, :variables, :value, :view_value, :name ]
4
+
5
+ class Action < Struct.new(*ACTION_MEMBERS)
6
+ # Create a new Action instance.
7
+ #
8
+ # @param [Hash, #values_at] hash used to seed new Action instance
9
+ # @return [Action] action with the given defaults from hash
10
+ # @author manveru
11
+ def self.create(hash = {})
12
+ new(*hash.values_at(*ACTION_MEMBERS))
13
+ end
14
+
15
+ # Call the Action instance, will insert itself temporarily into Current.actions during the render operation so even in nested calls one can still access all other Action instances.
16
+ # Will initialize the assigned node and call Action#render
17
+ #
18
+ # @return [String] The rendition of all nested calls
19
+ # @see Action#render Node#action_found
20
+ # @author manveru
21
+ def call
22
+ Current.actions << self
23
+ self.instance = node.new
24
+ self.variables[:content] ||= nil
25
+ render
26
+ ensure
27
+ Current.actions.delete(self)
28
+ end
29
+
30
+ # @return [Binding] binding of the instance for this Action
31
+ # @see Node#binding
32
+ # @author manveru
33
+ def binding
34
+ instance.binding
35
+ end
36
+
37
+ # Copy the instance variable names and values from given
38
+ # from_action#instance into the Action#variables of the action this method
39
+ # is called on.
40
+ #
41
+ # @param [Action #instance] from_action
42
+ # @return [Action] from_action
43
+ # @see Action#wrap_in_layout
44
+ # @author manveru
45
+ def sync_variables(from_action)
46
+ instance = from_action.instance
47
+
48
+ instance.instance_variables.each{|iv|
49
+ iv_value = instance.instance_variable_get(iv)
50
+ iv_name = iv.to_s[1..-1]
51
+ self.variables[iv_name.to_sym] = iv_value
52
+ }
53
+
54
+ from_action
55
+ end
56
+
57
+ # Copy Action#variables as instance variables into the given binding.
58
+ #
59
+ # This relies on Innate::STATE, so should be thread-safe and doesn't depend
60
+ # on Innate::Current::actions order.
61
+ # So we avoid nasty business with Objectspace#_id2ref which may not work on
62
+ # all ruby implementations and seems to cause other problems as well.
63
+ #
64
+ # @param [Binding #eval] binding
65
+ # @return [NilClass] there is no indication of failure or success
66
+ # @see View::ERB::render
67
+ # @author manveru
68
+ def copy_variables(binding = self.binding)
69
+ return unless variables.any?
70
+
71
+ STATE.sync do
72
+ STATE[:action_variables] = self.variables
73
+
74
+ binding.eval('
75
+ STATE[:action_variables].each do |iv, value|
76
+ instance_variable_set("@#{iv}", value)
77
+ end')
78
+
79
+ STATE[:action_variables] = nil
80
+ end
81
+ end
82
+
83
+ def render
84
+ instance.wrap_action_call(self) do
85
+ self.value = instance.__send__(method, *params) if method
86
+ self.view_value = File.read(view) if view
87
+ end
88
+
89
+ content_type, body = send(Innate.options.action.wish[wish] || :as_html)
90
+ Current.response['Content-Type'] ||= content_type
91
+
92
+ body
93
+ end
94
+
95
+ # @return [Array] Content-Type and rendered action
96
+ # @see Action#render Action#wrap_in_layout
97
+ # @author manveru
98
+ def as_html
99
+ return 'text/html', wrap_in_layout{ fulfill_wish(view_value || value) }
100
+ end
101
+
102
+ # @return [Array] Content-Type and rendered action
103
+ # @see Action#render Action#wrap_in_layout
104
+ # @author manveru
105
+ def as_yaml
106
+ require 'yaml'
107
+ return 'text/yaml', (value || view_value).to_yaml
108
+ end
109
+
110
+ # @return [Array] Content-Type and rendered action
111
+ # @see Action#render Action#wrap_in_layout
112
+ # @author manveru
113
+ def as_json
114
+ require 'json'
115
+ return 'application/json', (value || view_value).to_json
116
+ end
117
+
118
+ # @param [String, #to_str] string to be rendered
119
+ # @return [String] The rendered result of the templating engine
120
+ # @raise [RuntimeError] if no suitable templating engine was found
121
+ # @see Action#as_html
122
+ # @author manveru
123
+ def fulfill_wish(string)
124
+ way = File.basename(view).gsub!(/.*?#{wish}\./, '') if view
125
+ way ||= node.provide[wish] || node.provide['html']
126
+
127
+ if way
128
+ # Rack::Mime.mime_type(".#{wish}", 'text/html')
129
+ View.get(way).render(self, string)
130
+ else
131
+ raise("No templating engine was found for %p" % way)
132
+ end
133
+ end
134
+
135
+ def wrap_in_layout
136
+ return yield unless layout
137
+
138
+ action = dup
139
+ action.view, action.method = layout_view_or_method(*layout)
140
+ action.layout = nil
141
+ action.sync_variables(self)
142
+ action.variables[:content] = yield
143
+ action.call
144
+ end
145
+
146
+ def layout_view_or_method(name, arg)
147
+ return arg, nil if name == :layout || name == :view
148
+ return nil, arg
149
+ end
150
+
151
+ #Try to figure out a sane name for current action.
152
+ def name
153
+ File.basename((method || view).to_s).split('.').first
154
+ end
155
+ end
156
+ end