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,89 @@
1
+ module Rack
2
+ module Handler
3
+ autoload :Thin, 'rack/handler/thin'
4
+ autoload :Ebb, 'ebb'
5
+ autoload :SwiftipliedMongrel, 'rack/handler/swiftiplied_mongrel'
6
+
7
+ register 'thin', 'Rack::Handler::Thin'
8
+ register 'ebb', 'Rack::Handler::Ebb'
9
+ register 'smongrel', 'Rack::Handler::SwiftipliedMongrel'
10
+ end
11
+ end
12
+
13
+ module Innate
14
+
15
+ # Lightweight wrapper around Rack::Handler, will apply our options in a
16
+ # unified manner and deal with adapters that don't like to do what we want or
17
+ # where Rack doesn't want to take a stand.
18
+
19
+ module Adapter
20
+ class << self
21
+
22
+ # Pass given app to the Handler, handler is chosen based on
23
+ # config.adapter option.
24
+ # If there is a method named start_name_of_adapter it will be run instead
25
+ # of the default run method of the handler, this makes it easy to define
26
+ # custom startup of handlers for your server of choice
27
+ def start(app, options = Innate.options)
28
+ adapter_name = options[:adapter].to_s.downcase
29
+ config = { :Host => options[:host], :Port => options[:port] }
30
+ Log.debug "Innate uses #{adapter_name}"
31
+
32
+ if respond_to?(method = "start_#{adapter_name}")
33
+ send(method, app, config)
34
+ else
35
+ Rack::Handler.get(adapter_name).run(app, config)
36
+ end
37
+ end
38
+
39
+ # Due to buggy autoload on Ruby 1.8 we have to require 'ebb' manually.
40
+ # This most likely happens because autoload doesn't respect the require
41
+ # of rubygems and uses the C require directly.
42
+ def start_ebb(app, config)
43
+ require 'ebb'
44
+ Rack::Handler.get('ebb').run(app, config)
45
+ end
46
+
47
+ # We want webrick to use our logger.
48
+
49
+ def start_webrick(app, config)
50
+ handler = Rack::Handler.get('webrick')
51
+ config = {
52
+ :BindAddress => config[:Host],
53
+ :Port => config[:Port],
54
+ :Logger => Log,
55
+ :AccessLog => [
56
+ [Log, ::WEBrick::AccessLog::COMMON_LOG_FORMAT],
57
+ [Log, ::WEBrick::AccessLog::REFERER_LOG_FORMAT]]
58
+ }
59
+
60
+ handler.run(app, config)
61
+ end
62
+
63
+ # Thin shouldn't give excessive output, especially not to $stdout
64
+
65
+ def start_thin(app, config)
66
+ require 'thin'
67
+ handler = Rack::Handler.get('thin')
68
+ ::Thin::Logging.silent = true
69
+ handler.run(app, config)
70
+ end
71
+
72
+ # swiftcore has its own handler outside of rack
73
+
74
+ def start_emongrel(app, config)
75
+ require 'swiftcore/evented_mongrel'
76
+ handler = Rack::Handler.get('emongrel')
77
+ handler.run(app, config)
78
+ end
79
+
80
+ # swiftcore has its own handler outside of rack
81
+
82
+ def start_smongrel(app, config)
83
+ require 'swiftcore/swiftiplied_mongrel'
84
+ handler = Rack::Handler.get('smongrel')
85
+ handler.run(app, config)
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,117 @@
1
+ module Innate
2
+ # Cache manager and wrapper.
3
+ #
4
+ # Provides a convenient wrapper around caches to keep method name confusion
5
+ # at a minimum while still having short and meaningful method names for every
6
+ # cache instance.
7
+ #
8
+ # The default caching is specified in lib/innate.rb in the config section.
9
+ # At the time of writing it defaults to Innate::Cache::Memory but can be
10
+ # changed easily.
11
+ #
12
+ # Configuration has to be done before Innate::setup_dependencies is being
13
+ # called.
14
+ #
15
+ # Configuration:
16
+ #
17
+ # Innate.options.cache do |cache|
18
+ # cache.names = [:session, :user]
19
+ # cache.session = Innate::Cache::Marshal
20
+ # cache.user = Innate::Cache::YAML
21
+ # end
22
+ #
23
+ # Usage for storing:
24
+ #
25
+ # # Storing with a time to live (10 seconds)
26
+ # Innate::Cache.user.store(:manveru, "Michael Fellinger", :ttl => 10)
27
+ #
28
+ # # Storing indefinitely
29
+ # Innate::Cache.user[:Pistos] = "unknown"
30
+ # # or without :ttl argument
31
+ # Innate::Cache.user.store(:Pistos, "unknown")
32
+ #
33
+ # Usage for retrieving:
34
+ #
35
+ # # we stored this one for 10 seconds
36
+ # Innate::Cache.user.fetch(:manveru, 'not here anymore')
37
+ # # => "Michael Fellinger"
38
+ # sleep 11
39
+ # Innate::Cache.user.fetch(:manveru, 'not here anymore')
40
+ # # => "not here anymore"
41
+ #
42
+ # Innate::Cache.user[:Pistos]
43
+ # # => "unknown"
44
+ # Innate::Cache.user.fetch(:Pistos)
45
+ # # => "unknown"
46
+ #
47
+ #
48
+ # For more details and to find out how to implement your own cache please
49
+ # read the documentation of Innate::Cache::API
50
+ #
51
+ # NOTE:
52
+ # * Some caches might expose their contents for everyone else on the same
53
+ # system, or even on connected systems. The rule as usual is, not to
54
+ # cache sensitive information.
55
+
56
+ class Cache
57
+ autoload :API, 'innate/cache/api'
58
+ autoload :DRb, 'innate/cache/drb'
59
+ autoload :YAML, 'innate/cache/yaml'
60
+ autoload :Memory, 'innate/cache/memory'
61
+ autoload :Marshal, 'innate/cache/marshal'
62
+ autoload :FileBased, 'innate/cache/file_based'
63
+
64
+ attr_reader :name, :instance
65
+
66
+ def initialize(name, klass = nil)
67
+ @name = name.to_s.dup.freeze
68
+
69
+ options = Innate.options
70
+
71
+ klass ||= options[:cache, @name.to_sym]
72
+ @instance = klass.new
73
+
74
+ @instance.cache_setup(
75
+ options.env.host,
76
+ options.env.user,
77
+ options.app.name,
78
+ @name
79
+ )
80
+ end
81
+
82
+ def self.setup
83
+ Innate.options.cache.names.each{|name| add(name) }
84
+ end
85
+
86
+ def self.register(cache)
87
+ key = cache.name
88
+ source = "def self.%s() @%s; end
89
+ def self.%s=(o) @%s = o; end" % [key, key, key, key]
90
+ self.class_eval(source, __FILE__, __LINE__)
91
+
92
+ self.send("#{key}=", cache)
93
+ end
94
+
95
+ def self.add(name)
96
+ register(new(name))
97
+ end
98
+
99
+ def clear
100
+ instance.cache_clear
101
+ end
102
+
103
+ def delete(*keys)
104
+ instance.cache_delete(*keys)
105
+ end
106
+
107
+ def fetch(key, default = nil)
108
+ instance.cache_fetch(key, default)
109
+ end
110
+ alias [] fetch
111
+
112
+ def store(key, value, options = {})
113
+ instance.cache_store(key, value, options)
114
+ end
115
+ alias []= store
116
+ end
117
+ end
@@ -0,0 +1,106 @@
1
+ module Innate
2
+ class Cache
3
+
4
+ # This is the API every Cache has to conform to.
5
+ #
6
+ # The default behaviour is tailored for the Memory cache, override any
7
+ # behaviour as you need.
8
+ #
9
+ # +key+ may be a String or Symbol
10
+ # +value+ is a Hash of serializable (as according to Marshal) objects
11
+ #
12
+ # Every cache instance has to respond to:
13
+ #
14
+ # ::new()
15
+ # #cache_setup(hostname, username, appname, cachename)
16
+ # #cache_clear()
17
+ # #cache_delete(*keys)
18
+ # #cache_fetch(key, default = nil)
19
+ # #cache_store(key, value, options = {})
20
+ #
21
+ # We are prefixing cache_ to make the intent clear and implementation
22
+ # easier, as there may be existing behaviour associated with the
23
+ # non-prefixed version.
24
+ #
25
+ # Also note that we create one instance per cache name-space.
26
+ module API
27
+ # Executed after #initialize and before any other method.
28
+ #
29
+ # Some parameters identifying the current process will be passed so
30
+ # caches that act in one global name-space can use them as a prefix.
31
+ #
32
+ # Treat all arguments as Strings.
33
+ #
34
+ # +hostname+ the hostname of the machine.
35
+ # +username+ user executing this process.
36
+ # +appname+ identifier for the application being executed.
37
+ # +cachename+ name-space of the cache, like 'session' or 'action'
38
+ def cache_setup(hostname, username, appname, cachename)
39
+ end
40
+
41
+ # Remove all key/value pairs from the cache.
42
+ # Should behave as if #delete had been called with all +keys+ as argument.
43
+ def cache_clear
44
+ clear
45
+ end
46
+
47
+ # Remove the corresponding key/value pair for each key passed.
48
+ # If removing is not an option it should set the corresponding value to nil.
49
+ #
50
+ # If only one key was deleted, answer with the corresponding value.
51
+ # If multiple keys were deleted, answer with an Array containing the values.
52
+ def cache_delete(key, *keys)
53
+ if keys.empty?
54
+ if value = yield(key)
55
+ value[:value]
56
+ end
57
+ else
58
+ [key, *keys].map{|k| cache_delete(k) }
59
+ end
60
+ end
61
+
62
+ # Answer with the value associated with the +key+, +nil+ if not found or
63
+ # expired.
64
+ def cache_fetch(key, default = nil)
65
+ value = default
66
+
67
+ if entry = yield(key)
68
+ if expires = entry[:expires]
69
+ if expires > Time.now
70
+ value = entry[:value]
71
+ else
72
+ cache_delete(key)
73
+ end
74
+ else
75
+ value = entry[:value]
76
+ end
77
+ end
78
+
79
+ return value
80
+ end
81
+
82
+ # Set +key+ to +value+.
83
+ #
84
+ # +options+ may be one of:
85
+ # :ttl => time to live in seconds if given in Numeric
86
+ # infinite or maximum if not given
87
+ #
88
+ # Usage:
89
+ # Cache.value.store(:num, 3, :ttl => 20)
90
+ # Cache.value.fetch(:num) # => 3
91
+ # sleep 21
92
+ # Cache.value.fetch(:num) # => nil
93
+ #
94
+ def cache_store(key, value, options = {})
95
+ ttl = options[:ttl]
96
+
97
+ value_hash = {:value => value}
98
+ value_hash[:expires] = Time.now + ttl if ttl
99
+
100
+ yield(key, value_hash)
101
+
102
+ return value
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,58 @@
1
+ require 'drb'
2
+
3
+ module Innate
4
+ module Cache
5
+
6
+ # Cache utilizing a DRb server.
7
+ #
8
+ # You will need to run a corresponding DRb server to use this cache. The
9
+ # example below is using a normal Hash, but it is recommended to use a
10
+ # thread-safe alternative like SyncHash.
11
+ #
12
+ # Example for DRb server:
13
+ #
14
+ # require 'drb'
15
+ #
16
+ # URI = "druby://127.0.0.1:9069"
17
+ # CACHE = {}
18
+ #
19
+ # $SAFE = 1 # disable eval and friends
20
+ #
21
+ # DRb.start_service(URI, CACHE)
22
+ # DRb.thread.join
23
+ #
24
+ # Usage for all caches:
25
+ #
26
+ # Innate.options.cache.default = Innate::Cache::DRb
27
+ #
28
+ # Usage for sessions only:
29
+ #
30
+ # Innate.options.cache.session = Innate::Cache::DRb
31
+ class DRb
32
+ include Cache::API
33
+
34
+ OPTIONS = {:address => '127.0.0.1', :port => 9069}
35
+
36
+ def cache_setup(*args)
37
+ address, port = OPTIONS.values_at(:address, :port)
38
+ @store = DRbObject.new(nil, "druby://#{address}:#{port}")
39
+ end
40
+
41
+ def cache_clear
42
+ @store.clear
43
+ end
44
+
45
+ def cache_store(*args)
46
+ super{|key, value| @store[key] = value }
47
+ end
48
+
49
+ def cache_fetch(*args)
50
+ super{|key| @store[key] }
51
+ end
52
+
53
+ def cache_delete(*args)
54
+ super{|key| @store.delete(key) }
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,39 @@
1
+ module Innate
2
+ class Cache
3
+
4
+ # Used by caches that serialize their contents to the filesystem.
5
+ module FileBased
6
+ def cache_setup(*args)
7
+ @prefix = args.compact.join('-')
8
+
9
+ @dir = File.join(Dir.tmpdir, self.class::DIR)
10
+ FileUtils.mkdir_p(@dir)
11
+
12
+ @filename = File.join(@dir, @prefix + self.class::EXT)
13
+ @store = self.class::STORE.new(@filename)
14
+ end
15
+
16
+ def cache_clear
17
+ FileUtils.mkdir_p(@dir)
18
+ FileUtils.rm_f(@filename)
19
+ @store = self.class::STORE.new(@filename)
20
+ end
21
+
22
+ def cache_store(*args)
23
+ super{|key, value| transaction{|store| store[key] = value } }
24
+ end
25
+
26
+ def cache_fetch(*args)
27
+ super{|key| transaction{|store| store[key] } }
28
+ end
29
+
30
+ def cache_delete(*args)
31
+ super{|key| transaction{|store| store.delete(key) } }
32
+ end
33
+
34
+ def transaction(&block)
35
+ Innate.sync{ @store.transaction(&block) }
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,17 @@
1
+ require 'pstore'
2
+
3
+ module Innate
4
+ class Cache
5
+ # Keeps every cache in a separate file like this:
6
+ #
7
+ # /tmp/innate-cache-marshal/delta-manveru-session.marshal
8
+ class Marshal
9
+ include Cache::API
10
+ include Cache::FileBased
11
+
12
+ STORE = ::PStore
13
+ DIR = 'innate-cache-marshal'
14
+ EXT = '.marshal'
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,22 @@
1
+ module Innate
2
+ class Cache
3
+ # Memory cache is simply a Hash with the Cache::API, it's the reference
4
+ # implementation for every other cache.
5
+
6
+ class Memory < Hash
7
+ include Cache::API
8
+
9
+ def cache_store(*args)
10
+ super{|key, value| self[key] = value }
11
+ end
12
+
13
+ def cache_fetch(*args)
14
+ super{|key| self[key] }
15
+ end
16
+
17
+ def cache_delete(*args)
18
+ super{|key| delete(key) }
19
+ end
20
+ end
21
+ end
22
+ end