manveru-innate 2009.02.25 → 2009.03.24

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/CHANGELOG +383 -0
  2. data/MANIFEST +17 -8
  3. data/README.md +222 -136
  4. data/Rakefile +7 -2
  5. data/example/provides.rb +28 -0
  6. data/innate.gemspec +19 -10
  7. data/lib/innate/action.rb +21 -47
  8. data/lib/innate/adapter.rb +65 -56
  9. data/lib/innate/cache.rb +16 -8
  10. data/lib/innate/dynamap.rb +39 -29
  11. data/lib/innate/helper/aspect.rb +60 -0
  12. data/lib/innate/helper/cgi.rb +2 -0
  13. data/lib/innate/helper/link.rb +43 -11
  14. data/lib/innate/helper/partial.rb +6 -5
  15. data/lib/innate/helper.rb +10 -13
  16. data/lib/innate/log/hub.rb +1 -0
  17. data/lib/innate/log.rb +3 -6
  18. data/lib/{rack → innate}/middleware_compiler.rb +19 -12
  19. data/lib/innate/mock.rb +3 -2
  20. data/lib/innate/node.rb +573 -179
  21. data/lib/innate/options/dsl.rb +46 -6
  22. data/lib/innate/options/stub.rb +7 -0
  23. data/lib/innate/options.rb +14 -93
  24. data/lib/innate/request.rb +21 -7
  25. data/lib/innate/response.rb +12 -0
  26. data/lib/innate/route.rb +2 -3
  27. data/lib/innate/session.rb +37 -20
  28. data/lib/innate/spec.rb +4 -0
  29. data/lib/innate/state/fiber.rb +14 -7
  30. data/lib/innate/state/thread.rb +10 -2
  31. data/lib/innate/state.rb +8 -11
  32. data/lib/innate/traited.rb +14 -6
  33. data/lib/innate/trinity.rb +0 -4
  34. data/lib/innate/version.rb +1 -1
  35. data/lib/innate/view/erb.rb +4 -2
  36. data/lib/innate/view/none.rb +2 -2
  37. data/lib/innate/view.rb +14 -21
  38. data/lib/innate.rb +49 -30
  39. data/spec/helper.rb +8 -0
  40. data/spec/innate/action/layout.rb +9 -6
  41. data/spec/innate/cache/common.rb +3 -3
  42. data/spec/innate/helper/aspect.rb +3 -5
  43. data/spec/innate/helper/flash.rb +1 -1
  44. data/spec/innate/helper/link.rb +45 -2
  45. data/spec/innate/helper/partial.rb +34 -10
  46. data/spec/innate/helper/view/loop.erb +1 -1
  47. data/spec/innate/helper/view/recursive.erb +1 -1
  48. data/spec/innate/node/mapping.rb +37 -0
  49. data/spec/innate/node/node.rb +142 -0
  50. data/spec/innate/node/resolve.rb +82 -0
  51. data/spec/innate/node/{another_layout → view/another_layout}/another_layout.erb +0 -0
  52. data/spec/innate/node/{bar.html → view/bar.erb} +0 -0
  53. data/spec/innate/node/{foo.html.erb → view/foo.html.erb} +0 -0
  54. data/spec/innate/node/{only_view.html → view/only_view.erb} +0 -0
  55. data/spec/innate/node/view/with_layout.erb +1 -0
  56. data/spec/innate/node/wrap_action_call.rb +83 -0
  57. data/spec/innate/options.rb +28 -6
  58. data/spec/innate/provides/list.html.erb +1 -0
  59. data/spec/innate/provides/list.txt.erb +1 -0
  60. data/spec/innate/provides.rb +99 -0
  61. data/spec/innate/request.rb +23 -10
  62. data/spec/innate/route.rb +2 -4
  63. data/spec/innate/session.rb +1 -1
  64. data/spec/innate/state/fiber.rb +57 -0
  65. data/spec/innate/state/thread.rb +40 -0
  66. metadata +20 -11
  67. data/lib/rack/reloader.rb +0 -192
  68. data/spec/innate/node/with_layout.erb +0 -3
  69. data/spec/innate/node.rb +0 -224
@@ -42,7 +42,7 @@ module Innate
42
42
  # # => 9
43
43
  #
44
44
  class Options
45
- def initialize(name, parent = self, &block)
45
+ def initialize(name, parent = self)
46
46
  @name, @parent, = name, parent
47
47
  @hash = {}
48
48
  yield(self) if block_given?
@@ -76,11 +76,12 @@ module Innate
76
76
  # @param [Object] value may be anything
77
77
  # @param [Hash] other optional Hash containing meta-data
78
78
  # :doc, :value keys will be ignored
79
- def o(doc, key, value, other = {}, &block)
79
+ def option(doc, key, value, other = {}, &block)
80
80
  trigger = block || other[:trigger]
81
81
  convert = {:doc => doc.to_s, :value => value, :trigger => trigger}
82
82
  @hash[key.to_sym] = other.merge(convert)
83
83
  end
84
+ alias o option
84
85
 
85
86
  # To avoid lookup on the parent, we can set a default to the internal Hash.
86
87
  # Parameters as in {Options#o}, but without the +key+.
@@ -111,6 +112,12 @@ module Innate
111
112
  end
112
113
  end
113
114
 
115
+ # @param [Array] keys
116
+ # @param [Object] value
117
+ def set_value(keys, value)
118
+ get(*keys)[:value] = value
119
+ end
120
+
114
121
  # Retrieve only the :value from the value hash if found via +keys+.
115
122
  def [](*keys)
116
123
  if value = get(*keys)
@@ -125,6 +132,8 @@ module Innate
125
132
  if ns = @hash[key.to_sym]
126
133
  ns[:value] = value
127
134
  ns[:trigger].call(value) if ns[:trigger].respond_to?(:call)
135
+ elsif existing = get(key)
136
+ option(existing[:doc].to_s.dup, key, value)
128
137
  else
129
138
  raise(ArgumentError, "No key for %p exists" % [key])
130
139
  end
@@ -140,17 +149,25 @@ module Innate
140
149
  end
141
150
 
142
151
  def merge!(hash)
143
- hash.each do |key, value|
144
- self[key] = value
152
+ hash.each_pair do |key, value|
153
+ set_value(key.to_s.split('.'), value)
145
154
  end
146
155
  end
147
156
 
148
- include Enumerable
157
+ def to_hash
158
+ @hash
159
+ end
149
160
 
150
- def each(&block)
161
+ def each_option(&block)
151
162
  @hash.each(&block)
152
163
  end
153
164
 
165
+ def each_pair
166
+ @hash.each do |key, values|
167
+ yield(key, self[key])
168
+ end
169
+ end
170
+
154
171
  def inspect
155
172
  @hash.inspect
156
173
  end
@@ -159,4 +176,27 @@ module Innate
159
176
  q.pp_hash @hash
160
177
  end
161
178
  end
179
+
180
+ # extend your class with this
181
+ module Optional
182
+ def self.included(into)
183
+ into.extend(SingletonMethods)
184
+
185
+ snaked = into.name.split('::').last
186
+ snaked = snaked.gsub(/\B[A-Z][^A-Z]/, '_\&').downcase.gsub(' ', '_')
187
+
188
+ options = Innate.options.sub(snaked)
189
+ into.instance_variable_set(:@options, options)
190
+ end
191
+
192
+ module SingletonMethods
193
+ attr_reader :options
194
+ end
195
+
196
+ private
197
+
198
+ def options
199
+ self.class.options
200
+ end
201
+ end
162
202
  end
@@ -0,0 +1,7 @@
1
+ module Innate
2
+ # this is just a stub so other modules can register their options in here,
3
+ # the real options are set in lib/innate.rb
4
+
5
+ class << self; attr_reader :options; end
6
+ @options = Options.new('Innate')
7
+ end
@@ -1,116 +1,37 @@
1
- require 'innate/options/dsl'
2
-
3
1
  module Innate
4
- @options = Options.new(:innate)
5
-
6
- # attr_accessor is faster
7
- class << self; attr_accessor :options; end
2
+ # this has to be run after a couple of other files have been required
8
3
 
9
- # This has to speak for itself.
10
4
  options.dsl do
11
- o "IP address or hostname that we respond to - 0.0.0.0 for all",
12
- :host, "0.0.0.0", :short => :H
13
-
14
- o "Port for the server",
15
- :port, 7000, :short => :p
16
-
17
5
  o "Indicate that calls Innate::start will be ignored",
18
6
  :started, false
19
7
 
20
- o "Web server to run on",
21
- :adapter, :webrick, :short => :a
22
-
23
8
  o "Will send ::setup to each element during Innate::start",
24
9
  :setup, [Innate::Cache, Innate::Node]
25
10
 
26
- o "Headers that will be merged into the response before Node::call",
27
- :header, {'Content-Type' => 'text/html'}
28
-
29
11
  o "Trap this signal to issue shutdown, nil/false to disable trap",
30
12
  :trap, 'SIGINT'
31
13
 
32
- o "Keep state in Thread or Fiber, fall back to Thread if Fiber not available",
33
- :state, :Fiber
14
+ o "The compiler for middleware",
15
+ :middleware_compiler, Innate::MiddlewareCompiler
34
16
 
35
17
  o "Indicates which default middleware to use, (:dev|:live)",
36
18
  :mode, :dev
37
19
 
38
- trigger(:mode){|v| Innate.middleware_recompile(v) }
39
-
40
- sub :log do
41
- o "Array of parameters for Logger.new, default to stderr for CGI",
42
- :params, [$stderr]
43
-
44
- o "Use ANSI colors for logging, nil does auto-detection by checking for #tty?",
45
- :color, nil
46
- end
47
-
48
- sub :redirect do
49
- o "Default response HTTP status on redirect",
50
- :status, 302
51
- end
52
-
53
- sub :env do
54
- o "Hostname of this machine",
55
- :host, ENV['HOSTNAME'] # FIXME: cross-platform
56
-
57
- o "Username executing the application",
58
- :user, ENV['USER'] # FIXME: cross-platform
59
- end
20
+ o "The directories this application resides in",
21
+ :roots, [File.dirname($0)]
60
22
 
61
- sub :app do
62
- o "Unique identifier for this application",
63
- :name, 'pristine'
23
+ o "The directories containing static files to be served",
24
+ :publics, ['public']
64
25
 
65
- o "Root directory containing the application",
66
- :root, File.dirname($0)
26
+ o "Directories containing the view templates",
27
+ :views, ['view']
67
28
 
68
- o "Root directory for view templates, relative to app subdir",
69
- :view, '/view'
29
+ o "Directories containing the layout templates",
30
+ :layouts, ['layout']
70
31
 
71
- o "Root directory for layout templates, relative to app subdir",
72
- :layout, '/layout'
32
+ o "Prefix used to create relative links",
33
+ :prefix, '/'
73
34
 
74
- o "Prefix of this application",
75
- :prefix, '/'
76
-
77
- o "Root directory for static public files",
78
- :public, '/public'
79
-
80
- trigger(:public){|v| Innate.middleware_recompile }
81
- end
82
-
83
- sub :session do
84
- o "Key for the session cookie",
85
- :key, 'innate.sid'
86
-
87
- o "Domain the cookie relates to, unspecified if false",
88
- :domain, false
89
-
90
- o "Path the cookie relates to",
91
- :path, '/'
92
-
93
- o "Use secure cookie",
94
- :secure, false
95
-
96
- o "Time of cookie expiration",
97
- :expires, Time.at(2147483647)
98
- end
99
-
100
- sub :cache do
101
- o "Assign a cache to each of these names on Innate::Cache::setup",
102
- :names, [:session]
103
-
104
- default "If no option for the cache name exists, fall back to this",
105
- Innate::Cache::Memory
106
- end
107
-
108
- sub :action do
109
- o "wish => Action#method",
110
- :wish, {'json' => :as_json, 'html' => :as_html, 'yaml' => :as_yaml}
111
-
112
- o "Create actions that have no method associated",
113
- :needs_method, false
114
- end
35
+ trigger(:mode){|v| Innate.middleware_recompile(v) }
115
36
  end
116
37
  end
@@ -84,7 +84,8 @@ module Innate
84
84
  # which you pass the keys.
85
85
  # Valid keys are objects that respond to :to_s
86
86
  #
87
- # @usage
87
+ # @example usage
88
+ #
88
89
  # request.params
89
90
  # # => {'name' => 'jason', 'age' => '45', 'job' => 'lumberjack'}
90
91
  # request.subset('name')
@@ -100,12 +101,25 @@ module Innate
100
101
  # Try to figure out the domain we are running on, this might work for some
101
102
  # deployments but fail for others, given the combination of servers in
102
103
  # front.
103
-
104
- def domain(path = '/')
105
- scheme = self.scheme || 'http'
106
- host = env['HTTP_HOST']
107
-
108
- URI("#{scheme}://#{host}#{path}")
104
+ #
105
+ # @example usage
106
+ #
107
+ # domain
108
+ # # => #<URI::HTTPS:0xb769ecb0 URL:https://localhost:7000/>
109
+ # domain('/foo')
110
+ # # => #<URI::HTTPS:0xb769ecb0 URL:https://localhost:7000/foo>
111
+ #
112
+ # @param [#to_s] path
113
+ #
114
+ # @return [URI]
115
+ #
116
+ # @api external
117
+ # @author manveru
118
+ def domain(path = nil, options = {})
119
+ uri = URI(self.url)
120
+ uri.path = path.to_s if path
121
+ uri.query = nil unless options[:keep_query]
122
+ uri
109
123
  end
110
124
 
111
125
  # Try to find out which languages the client would like to have and sort
@@ -5,6 +5,13 @@ module Innate
5
5
  # just do this.
6
6
 
7
7
  class Response < Rack::Response
8
+ include Optional
9
+
10
+ options.dsl do
11
+ o "Default headers, will not override headers already set",
12
+ :headers, {'Content-Type' => 'text/html'}
13
+ end
14
+
8
15
  attr_accessor :length
9
16
 
10
17
  def reset
@@ -14,5 +21,10 @@ module Innate
14
21
  self.length = 0
15
22
  self
16
23
  end
24
+
25
+ def finish
26
+ options.headers.each{|key, value| self[key] ||= value }
27
+ super
28
+ end
17
29
  end
18
30
  end
data/lib/innate/route.rb CHANGED
@@ -64,6 +64,7 @@ module Innate
64
64
  path << '/' if path.empty?
65
65
 
66
66
  if modified = resolve(path)
67
+ Log.debug("%s routes %p to %p" % [self.class.name, path, modified])
67
68
  env['PATH_INFO'] = modified
68
69
  end
69
70
 
@@ -71,15 +72,13 @@ module Innate
71
72
  end
72
73
 
73
74
  def resolve(path)
74
- request = Current.request
75
-
76
75
  self.class::ROUTES.each do |key, value|
77
76
  if key.is_a?(Regexp)
78
77
  md = path.match(key)
79
78
  return value % md.to_a[1..-1] if md
80
79
 
81
80
  elsif value.respond_to?(:call)
82
- new_path = value.call(path, Request.current)
81
+ new_path = value.call(path, Current.request)
83
82
  return new_path if new_path
84
83
 
85
84
  elsif value.respond_to?(:to_str)
@@ -3,16 +3,34 @@ module Innate
3
3
  # Mostly ported from Ramaze, but behaves lazy, no session will be created if
4
4
  # no session is used.
5
5
  #
6
- # The way we do it is to keep session data in memory until #flush is called,
7
- # at which point it will be persisted completely into the cache, no question
8
- # asked.
6
+ # We keep session data in memory until #flush is called, at which point it
7
+ # will be persisted completely into the cache, no question asked.
9
8
  #
10
- # NOTE:
11
- # * You may store anything in here that you may also store in the
12
- # corresponding store, usually it's best to keep it to things that are
13
- # safe to Marshal.
9
+ # You may store anything in here that you may also store in the corresponding
10
+ # store, usually it's best to keep it to things that are safe to Marshal.
11
+ #
12
+ # The default time of expiration is *
13
+ #
14
+ # Time.at(2147483647) # => Tue Jan 19 12:14:07 +0900 2038
15
+ #
16
+ # Hopefully we all have 64bit systems by then.
14
17
 
15
18
  class Session
19
+ include Optional
20
+
21
+ options.dsl do
22
+ o "Key for the session cookie",
23
+ :key, 'innate.sid'
24
+ o "Domain the cookie relates to, unspecified if false",
25
+ :domain, false
26
+ o "Path the cookie relates to",
27
+ :path, '/'
28
+ o "Use secure cookie",
29
+ :secure, false
30
+ o "Time of cookie expiration",
31
+ :expires, Time.at((1 << 31) - 1)
32
+ end
33
+
16
34
  attr_reader :cookie_set, :request, :response, :flash
17
35
 
18
36
  def initialize(request, response)
@@ -71,10 +89,6 @@ module Innate
71
89
  Innate::Cache.session
72
90
  end
73
91
 
74
- def options
75
- Innate.options[:session]
76
- end
77
-
78
92
  def set_cookie(response)
79
93
  return if @cookie_set || cookie
80
94
 
@@ -90,16 +104,19 @@ module Innate
90
104
  :expires => options.expires }
91
105
  end
92
106
 
93
- def entropy
94
- [ srand, rand, Time.now.to_f, rand, $$, rand, object_id ]
95
- end
96
-
97
107
  def generate_sid
98
- begin
99
- sid = Digest::SHA1.hexdigest(entropy.join)
100
- end while cache[sid]
101
-
102
- return sid
108
+ begin sid = sid_algorithm end while cache[sid]
109
+ sid
110
+ end
111
+
112
+ begin
113
+ require 'securerandom'
114
+ def sid_algorithm; SecureRandom.hex(32); end
115
+ rescue LoadError
116
+ def sid_algorithm
117
+ entropy = [ srand, rand, Time.now.to_f, rand, $$, rand, object_id ]
118
+ Digest::SHA2.hexdigest(entropy.join)
119
+ end
103
120
  end
104
121
  end
105
122
  end
data/lib/innate/spec.rb CHANGED
@@ -37,8 +37,12 @@ shared :session do
37
37
  end
38
38
 
39
39
  shared :mock do
40
+ Innate.setup_dependencies
41
+
40
42
  def get(*args) Innate::Mock.get(*args) end
41
43
  def post(*args) Innate::Mock.post(*args) end
44
+ def put(*args) Innate::Mock.put(*args) end
45
+ def delete(*args) Innate::Mock.delete(*args) end
42
46
  end
43
47
 
44
48
  shared :multipart do
@@ -9,11 +9,6 @@ module Innate
9
9
  # necessary right now but may be added.
10
10
  #
11
11
  # We subclass to keep your Ruby clean and polished.
12
- #
13
- # TODO:
14
- # * 1.9.1 includes a patch from matz that will call #initialize, so we can
15
- # remove our ::new hack, just have to get my hands on a properly
16
- # compiling version of 1.9.1
17
12
  class Fiber < ::Fiber
18
13
  attr_accessor :state
19
14
 
@@ -33,6 +28,10 @@ module Innate
33
28
  def key?(key)
34
29
  state.key?(key)
35
30
  end
31
+
32
+ def keys
33
+ state.keys
34
+ end
36
35
  end
37
36
 
38
37
  module State
@@ -41,11 +40,11 @@ module Innate
41
40
  # available.
42
41
  class Fiber
43
42
  def [](key)
44
- Innate::Fiber.current[key]
43
+ ::Fiber.current[key]
45
44
  end
46
45
 
47
46
  def []=(key, value)
48
- Innate::Fiber.current[key] = value
47
+ ::Fiber.current[key] = value
49
48
  end
50
49
 
51
50
  # We don't use Fiber in a concurrent manner and they don't run
@@ -62,6 +61,14 @@ module Innate
62
61
  def sync
63
62
  yield
64
63
  end
64
+
65
+ def defer
66
+ a = Innate::Fiber.current
67
+ ::Thread.new do
68
+ b = Innate::Fiber.new{ a.keys.each{|k| b[k] = a[k] }; yield }
69
+ b.resume
70
+ end
71
+ end
65
72
  end
66
73
  end
67
74
  end
@@ -5,7 +5,7 @@ module Innate
5
5
  # In case fibers are not available we fall back to this wrapper.
6
6
  #
7
7
  # It will raise errors happening inside the wrapping Thread even if
8
- # Thread::raise_on_exception is false.
8
+ # Thread::abort_on_exception is false.
9
9
  #
10
10
  # For things that require a mutex in a threaded environment, use
11
11
  # STATE#sync, if Fiber is available no mutex will be used.
@@ -24,7 +24,10 @@ module Innate
24
24
  # Execute given block in a new Thread and rescue any exceptions before
25
25
  # they reach Thread::new, so in case Thread::raise_on_exception is false
26
26
  # we can still reraise the error outside of the Thread.
27
-
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.
28
31
  def wrap
29
32
  value = ::Thread.new{ begin; yield; rescue Exception => ex; ex; end }.value
30
33
  raise(value) if Exception === value
@@ -34,6 +37,11 @@ module Innate
34
37
  def sync(&block)
35
38
  SEMAPHORE.synchronize(&block)
36
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
37
45
  end
38
46
  end
39
47
  end
data/lib/innate/state.rb CHANGED
@@ -1,15 +1,8 @@
1
1
  module Innate
2
- state = options[:state]
3
-
4
- if state == :Fiber
5
- begin
6
- require 'innate/state/fiber'
7
- STATE = State::Fiber.new
8
- rescue LoadError
9
- require 'innate/state/thread'
10
- STATE = State::Thread.new
11
- end
12
- else
2
+ begin
3
+ require 'innate/state/fiber'
4
+ STATE = State::Fiber.new
5
+ rescue LoadError
13
6
  require 'innate/state/thread'
14
7
  STATE = State::Thread.new
15
8
  end
@@ -26,5 +19,9 @@ module Innate
26
19
  def sync(&block)
27
20
  STATE.sync(&block)
28
21
  end
22
+
23
+ def defer(&block)
24
+ STATE.defer(&block)
25
+ end
29
26
  end
30
27
  end
@@ -6,7 +6,8 @@ module Innate
6
6
  # By using {Traited#ancestral_trait} you will get nicely inherited
7
7
  # configuration, where keys later in the ancestors will take precedence.
8
8
  #
9
- # @usage
9
+ # @example usage
10
+ #
10
11
  # class Foo
11
12
  # include Innate::Traited
12
13
  # trait :hello => 'Hello'
@@ -60,13 +61,20 @@ module Innate
60
61
  # # => {:three => :drei, :two => :zwei, :one => :eins, :first => :overwritten}
61
62
  def ancestral_trait
62
63
  result = {}
64
+ each_ancestral_trait{|trait| result.merge!(trait) }
65
+ result
66
+ end
63
67
 
64
- ancs = respond_to?(:ancestors) ? ancestors : self.class.ancestors
65
- ancs.reverse_each do |anc|
66
- result.update(anc.trait) if anc.respond_to?(:trait)
67
- end
68
+ def ancestral_trait_values(key)
69
+ result = []
70
+ each_ancestral_trait{|trait| result << trait[key] if trait.key?(key) }
71
+ result
72
+ end
68
73
 
69
- result.merge!(trait)
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) }
70
78
  end
71
79
 
72
80
  # trait for self.class if we are an instance
@@ -14,9 +14,5 @@ module Innate
14
14
  def action
15
15
  actions.last
16
16
  end
17
-
18
- def action=(arg)
19
- raise "You have to modify Current::actions or use Current::action.wrap"
20
- end
21
17
  end
22
18
  end
@@ -1,3 +1,3 @@
1
1
  module Innate
2
- VERSION = "2009.02.25"
2
+ VERSION = "2009.03.24"
3
3
  end
@@ -3,14 +3,16 @@ require 'erb'
3
3
  module Innate
4
4
  module View
5
5
  module ERB
6
- def self.render(action, string)
6
+ def self.call(action, string)
7
7
  return unless string.respond_to?(:to_str)
8
8
 
9
9
  action.copy_variables
10
10
 
11
11
  erb = ::ERB.new(string.to_str, nil, '%<>')
12
12
  erb.filename = (action.view || action.method).to_s
13
- erb.result(action.binding)
13
+ html = erb.result(action.binding)
14
+
15
+ return html, 'text/html'
14
16
  end
15
17
  end
16
18
  end
@@ -1,8 +1,8 @@
1
1
  module Innate
2
2
  module View
3
3
  module None
4
- def self.render(action, string)
5
- string
4
+ def self.call(action, string)
5
+ return string, 'text/html'
6
6
  end
7
7
  end
8
8
  end