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