manveru-innate 2009.02.06

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.
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