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
@@ -0,0 +1,39 @@
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::raise_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
+ def wrap
29
+ value = ::Thread.new{ begin; yield; rescue Exception => ex; ex; end }.value
30
+ raise(value) if Exception === value
31
+ return value
32
+ end
33
+
34
+ def sync(&block)
35
+ SEMAPHORE.synchronize(&block)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,20 @@
1
+ module Innate
2
+ module Traited
3
+ TRAITS = Hash.new{|h,k| h[k] = {}}
4
+
5
+ def self.included(into)
6
+ into.extend(self)
7
+ end
8
+
9
+ def trait(hash = nil)
10
+ hash ? TRAITS[self].update(hash) : TRAITS[self]
11
+ end
12
+
13
+ def ancestral_trait
14
+ ancs = respond_to?(:ancestors) ? ancestors : self.class.ancestors
15
+ ancs.reverse.inject({}){|s,v|
16
+ v.respond_to?(:trait) ? s.update(v.trait) : s
17
+ }.merge(trait)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,22 @@
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
+
18
+ def action=(arg)
19
+ raise "You have to modify Current::actions or use Current::action.wrap"
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module Innate
2
+ VERSION = "2009.02.06"
3
+ end
@@ -0,0 +1,67 @@
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
+ # Try to obtain given engine by its registered name.
12
+
13
+ def get(engine_or_ext)
14
+ return unless engine_or_ext
15
+ eoe = engine_or_ext.to_s
16
+
17
+ if klass = TEMP[eoe]
18
+ return klass
19
+ elsif klass = ENGINE[eoe]
20
+ TEMP[eoe] = obtain(klass)
21
+ else
22
+ TEMP[eoe] = const_get(eoe.capitalize)
23
+ end
24
+ end
25
+
26
+ # We need to put this in a Mutex because simultanous calls for the same
27
+ # class will cause race conditions and one call may return the wrong class
28
+ # on the first request (before TEMP is set).
29
+ # No mutex is used in Fiber environment, see Innate::State and subclasses.
30
+
31
+ def obtain(klass)
32
+ STATE.sync do
33
+ obj = Object
34
+ klass.split('::').each{|e| obj = obj.const_get(e) }
35
+ obj
36
+ end
37
+ end
38
+
39
+ # Register given templating engine wrapper and extensions for later usage.
40
+ #
41
+ # +name+ : the class name of the templating engine wrapper
42
+ # +exts+ : any number of arguments will be turned into strings via #to_s
43
+ # that indicate which filename-extensions the templates may have.
44
+
45
+ def register(klass, *exts)
46
+ exts.each do |ext|
47
+ ext = ext.to_s
48
+ if k = ENGINE[ext]
49
+ Log.warn "#{ext} is assigned to #{k} already"
50
+ else
51
+ ENGINE[ext] = klass
52
+ end
53
+ end
54
+ end
55
+
56
+ # Combine Kernel#autoload and Innate::View::register
57
+
58
+ def auto_register(name, *exts)
59
+ autoload(name, "innate/view/#{name}".downcase)
60
+ register("#{self}::#{name}", *exts)
61
+ end
62
+
63
+ auto_register :None, :css
64
+ auto_register :None, :html, :htm
65
+ auto_register :ERB, :erb
66
+ end
67
+ end
@@ -0,0 +1,17 @@
1
+ require 'erb'
2
+
3
+ module Innate
4
+ module View
5
+ module ERB
6
+ def self.render(action, string = action.view)
7
+ return unless string.respond_to?(:to_str)
8
+
9
+ action.copy_variables
10
+
11
+ erb = ::ERB.new(string.to_str, nil, '%<>')
12
+ erb.filename = (action.view || action.method).to_s
13
+ erb.result(action.binding)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ module Innate
2
+ module View
3
+ module None
4
+ def self.render(action, string = nil)
5
+ string || action.view
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,62 @@
1
+ module Rack
2
+ class MiddlewareCompiler
3
+ COMPILED = {}
4
+
5
+ def self.build(name, &block)
6
+ COMPILED[name] ||= new(name, &block)
7
+ end
8
+
9
+ def self.build!(name, &block)
10
+ COMPILED[name] = new(name, &block)
11
+ end
12
+
13
+ attr_reader :middlewares, :name
14
+
15
+ def initialize(name)
16
+ @name = name
17
+ @middlewares = []
18
+ @compiled = nil
19
+ yield(self) if block_given?
20
+ end
21
+
22
+ # FIXME: Should we use `|` or `+`?
23
+ def use(*mws)
24
+ @middlewares = mws | @middlewares
25
+ end
26
+
27
+ def run(app)
28
+ @app = app
29
+ end
30
+
31
+ def cascade(*apps)
32
+ @app = Rack::Cascade.new(apps)
33
+ end
34
+
35
+ # Default application for Innate
36
+ def innate
37
+ cascade(
38
+ Rack::File.new('public'),
39
+ Innate::Current.new(Innate::Route.new, Innate::Rewrite.new))
40
+ end
41
+
42
+ def static(path)
43
+ require 'rack/contrib'
44
+ Rack::ConditionalGet.new(Rack::ETag.new(Rack::File.new(path)))
45
+ end
46
+
47
+ def call(env)
48
+ compile
49
+ @compiled.call(env)
50
+ end
51
+
52
+ def compiled?
53
+ @compiled
54
+ end
55
+
56
+ def compile
57
+ return self if compiled?
58
+ @compiled = @middlewares.inject(@app){|a,e| e.new(a) }
59
+ self
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,192 @@
1
+ # Copyright (c) 2008 Michael Fellinger m.fellinger@gmail.com
2
+ # All files in this distribution are subject to the terms of the Ruby license.
3
+
4
+ require 'pathname'
5
+
6
+ module Rack
7
+
8
+ # High performant source reloader
9
+ #
10
+ # This class acts as Rack middleware.
11
+ #
12
+ # It does not depend on Ramaze itself, but you might have to adjust the
13
+ # Reloader::Hooks module or include your own module to override the hooks.
14
+ # You also might have to set the Log constant.
15
+ #
16
+ # What makes it especially suited for use in a production environment is that
17
+ # any file will only be checked once and there will only be made one system
18
+ # call stat(2).
19
+ #
20
+ # Please note that this will not reload files in the background, it does so
21
+ # only when actively called
22
+ # In case of Ramaze it is performing a check/reload cycle at the start of
23
+ # every request, but also respects a cool down time, during which nothing will
24
+ # be done.
25
+ #
26
+ # After every reload the OPTIONS hash will be checked for changed options and
27
+ # assigned to the instance, so you may change options during the lifetime of
28
+ # your application.
29
+ #
30
+ # A number of hooks will be executed during the reload cycle, see
31
+ # Ramaze::ReloaderHooks for more information.
32
+
33
+ class Reloader
34
+ OPTIONS = {
35
+ # At most check every n seconds
36
+ # nil/false will never trigger the reload cycle
37
+ # 0 will cycle on every call
38
+ :cooldown => 2,
39
+
40
+ # Compiled files cannot be reloaded during runtime
41
+ :ignore => /\.so$/,
42
+
43
+ # Run cycle in a Thread.exclusive, by default no threads are used.
44
+ :thread => false,
45
+
46
+ # If you assign a block here it will be instance_evaled instead of
47
+ # calling cycle. This allows you to use for example EventMachine for
48
+ # well performing asynchronous cycling.
49
+ :control => nil, # lambda{ cycle },
50
+ }
51
+
52
+
53
+ # Dirty! keep track of this in an instance :(
54
+ # Find out how to reasonably cache racks builder
55
+ @@last ||= Time.now
56
+ @@cache ||= {}
57
+ @@mtimes ||= {}
58
+
59
+ def initialize(app)
60
+ @app = app
61
+ options_reload
62
+ end
63
+
64
+ def options_reload
65
+ @cooldown, @ignore, @control, @thread =
66
+ OPTIONS.values_at(:cooldown, :ignore, :control, :thread)
67
+ end
68
+
69
+ def call(env)
70
+ options_reload
71
+
72
+ if @cooldown and Time.now > @@last + @cooldown
73
+ if @control
74
+ instance_eval(&@control)
75
+ elsif @thread
76
+ Thread.exclusive{ cycle }
77
+ else
78
+ cycle
79
+ end
80
+
81
+ @@last = Time.now
82
+ end
83
+
84
+ @app.call(env)
85
+ end
86
+
87
+ def cycle
88
+ before_cycle
89
+
90
+ rotation do |file, stat|
91
+ if mtime = stat.mtime
92
+ if mtime > (@@mtimes[file] ||= mtime)
93
+ safe_load(file, mtime)
94
+ end
95
+ else
96
+ @@cache.delete(file)
97
+ end
98
+ end
99
+
100
+ after_cycle
101
+ end
102
+
103
+ # A safe Kernel::load, issuing the hooks depending on the results
104
+ def safe_load(file, mtime)
105
+ before_safe_load(file)
106
+ load(file)
107
+ after_safe_load_succeed(file)
108
+ rescue Object => ex
109
+ puts ex
110
+ after_safe_load_failed(file, ex)
111
+ ensure
112
+ @@mtimes[file] = mtime
113
+ end
114
+
115
+ def rotation
116
+ files = [$0, *$LOADED_FEATURES].uniq
117
+ paths = ['./', *$LOAD_PATH].uniq
118
+
119
+ files.each do |file|
120
+ next if file =~ @ignore
121
+ path, stat = figure_path(file, paths)
122
+
123
+ if path and stat
124
+ @@cache[file] = path
125
+ yield(path, stat)
126
+ else
127
+ # Mostly harmless
128
+ end
129
+ end
130
+ end
131
+
132
+ def figure_path(file, paths)
133
+ if cached = @@cache[file]
134
+ stat = ::File.stat(cached)
135
+ return cached, stat if stat.file?
136
+ elsif Pathname.new(file).absolute?
137
+ stat = ::File.stat(file)
138
+ return file, stat if stat.file? # do directories really end up in $" ?
139
+ end
140
+
141
+ paths.each do |possible_path|
142
+ path = ::File.join(possible_path, file)
143
+
144
+ begin
145
+ stat = ::File.stat(path)
146
+ return path, stat if stat.file?
147
+ rescue Errno::ENOENT, Errno::ENOTDIR
148
+ end
149
+ end
150
+
151
+ return nil
152
+ rescue Errno::ENOENT => ex
153
+ @@cache.delete(file)
154
+ retry
155
+ end
156
+
157
+ # Holds hooks that are called before and after #cycle and #safe_load
158
+ module Hooks
159
+ # Overwrite to add actions before the reload rotation is started.
160
+ def before_cycle
161
+ end
162
+
163
+ # Overwrite to add actions after the reload rotation has ended.
164
+ def after_cycle
165
+ end
166
+
167
+ # Overwrite to add actions before a file is Kernel::load-ed
168
+ def before_safe_load(file)
169
+ puts "reload #{file}" # Log.debug("reload #{file}")
170
+ end
171
+
172
+ # Overwrite to add actions after a file is Kernel::load-ed successfully,
173
+ # by default we clean the Cache for compiled templates and resolved actions.
174
+ def after_safe_load_succeed(file)
175
+ after_safe_load(file)
176
+ end
177
+
178
+ # Overwrite to add custom hook in addition to default Cache cleaning
179
+ def after_safe_load(file)
180
+ end
181
+
182
+ # Overwrite to add actions after a file is Kernel::load-ed unsuccessfully,
183
+ # by default we output an error-message with the exception.
184
+ def after_safe_load_failed(file, error)
185
+ puts error # Log.error(error)
186
+ end
187
+ end
188
+
189
+ include Hooks
190
+
191
+ end
192
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec/helper'
2
+
3
+ require 'example/hello'
4
+
5
+ describe 'example/hello' do
6
+ behaves_like :mock
7
+
8
+ should 'have index action' do
9
+ got = get('/')
10
+ got.status.should == 200
11
+ got['Content-Type'].should == 'text/html'
12
+ got.body.should == 'Hello, World!'
13
+ end
14
+ end