innate 2009.04

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. data/CHANGELOG +2981 -0
  2. data/COPYING +18 -0
  3. data/MANIFEST +127 -0
  4. data/README.md +563 -0
  5. data/Rakefile +35 -0
  6. data/example/app/retro_games.rb +60 -0
  7. data/example/app/todo/layout/default.xhtml +11 -0
  8. data/example/app/todo/spec/todo.rb +63 -0
  9. data/example/app/todo/start.rb +51 -0
  10. data/example/app/todo/view/index.xhtml +39 -0
  11. data/example/app/whywiki_erb/layout/wiki.html.erb +15 -0
  12. data/example/app/whywiki_erb/spec/wiki.rb +19 -0
  13. data/example/app/whywiki_erb/start.rb +42 -0
  14. data/example/app/whywiki_erb/view/edit.erb +6 -0
  15. data/example/app/whywiki_erb/view/index.erb +12 -0
  16. data/example/custom_middleware.rb +35 -0
  17. data/example/hello.rb +11 -0
  18. data/example/howto_spec.rb +35 -0
  19. data/example/link.rb +27 -0
  20. data/example/provides.rb +31 -0
  21. data/example/session.rb +38 -0
  22. data/innate.gemspec +29 -0
  23. data/lib/innate.rb +269 -0
  24. data/lib/innate/action.rb +150 -0
  25. data/lib/innate/adapter.rb +76 -0
  26. data/lib/innate/cache.rb +134 -0
  27. data/lib/innate/cache/api.rb +128 -0
  28. data/lib/innate/cache/drb.rb +58 -0
  29. data/lib/innate/cache/file_based.rb +41 -0
  30. data/lib/innate/cache/marshal.rb +17 -0
  31. data/lib/innate/cache/memory.rb +22 -0
  32. data/lib/innate/cache/yaml.rb +17 -0
  33. data/lib/innate/current.rb +37 -0
  34. data/lib/innate/dynamap.rb +96 -0
  35. data/lib/innate/helper.rb +183 -0
  36. data/lib/innate/helper/aspect.rb +124 -0
  37. data/lib/innate/helper/cgi.rb +54 -0
  38. data/lib/innate/helper/flash.rb +36 -0
  39. data/lib/innate/helper/link.rb +94 -0
  40. data/lib/innate/helper/redirect.rb +85 -0
  41. data/lib/innate/helper/render.rb +87 -0
  42. data/lib/innate/helper/send_file.rb +26 -0
  43. data/lib/innate/log.rb +20 -0
  44. data/lib/innate/log/color_formatter.rb +43 -0
  45. data/lib/innate/log/hub.rb +73 -0
  46. data/lib/innate/middleware_compiler.rb +65 -0
  47. data/lib/innate/mock.rb +49 -0
  48. data/lib/innate/node.rb +1025 -0
  49. data/lib/innate/options.rb +37 -0
  50. data/lib/innate/options/dsl.rb +202 -0
  51. data/lib/innate/options/stub.rb +7 -0
  52. data/lib/innate/request.rb +141 -0
  53. data/lib/innate/response.rb +23 -0
  54. data/lib/innate/route.rb +110 -0
  55. data/lib/innate/session.rb +121 -0
  56. data/lib/innate/session/flash.rb +94 -0
  57. data/lib/innate/spec.rb +23 -0
  58. data/lib/innate/state.rb +27 -0
  59. data/lib/innate/state/accessor.rb +130 -0
  60. data/lib/innate/state/fiber.rb +74 -0
  61. data/lib/innate/state/thread.rb +47 -0
  62. data/lib/innate/traited.rb +85 -0
  63. data/lib/innate/trinity.rb +18 -0
  64. data/lib/innate/version.rb +3 -0
  65. data/lib/innate/view.rb +60 -0
  66. data/lib/innate/view/erb.rb +15 -0
  67. data/lib/innate/view/etanni.rb +36 -0
  68. data/lib/innate/view/none.rb +9 -0
  69. data/spec/example/app/retro_games.rb +30 -0
  70. data/spec/example/hello.rb +13 -0
  71. data/spec/example/link.rb +25 -0
  72. data/spec/example/provides.rb +16 -0
  73. data/spec/example/session.rb +22 -0
  74. data/spec/helper.rb +10 -0
  75. data/spec/innate/action/layout.rb +107 -0
  76. data/spec/innate/action/layout/file_layout.xhtml +1 -0
  77. data/spec/innate/cache/common.rb +47 -0
  78. data/spec/innate/cache/marshal.rb +5 -0
  79. data/spec/innate/cache/memory.rb +5 -0
  80. data/spec/innate/cache/yaml.rb +5 -0
  81. data/spec/innate/dynamap.rb +22 -0
  82. data/spec/innate/helper.rb +86 -0
  83. data/spec/innate/helper/aspect.rb +75 -0
  84. data/spec/innate/helper/cgi.rb +37 -0
  85. data/spec/innate/helper/flash.rb +118 -0
  86. data/spec/innate/helper/link.rb +139 -0
  87. data/spec/innate/helper/redirect.rb +160 -0
  88. data/spec/innate/helper/render.rb +133 -0
  89. data/spec/innate/helper/send_file.rb +21 -0
  90. data/spec/innate/helper/view/aspect_hello.xhtml +1 -0
  91. data/spec/innate/helper/view/locals.xhtml +1 -0
  92. data/spec/innate/helper/view/loop.xhtml +4 -0
  93. data/spec/innate/helper/view/num.xhtml +1 -0
  94. data/spec/innate/helper/view/partial.xhtml +1 -0
  95. data/spec/innate/helper/view/recursive.xhtml +7 -0
  96. data/spec/innate/mock.rb +84 -0
  97. data/spec/innate/node/mapping.rb +37 -0
  98. data/spec/innate/node/node.rb +134 -0
  99. data/spec/innate/node/resolve.rb +82 -0
  100. data/spec/innate/node/view/another_layout/another_layout.xhtml +3 -0
  101. data/spec/innate/node/view/bar.xhtml +1 -0
  102. data/spec/innate/node/view/foo.html.xhtml +1 -0
  103. data/spec/innate/node/view/only_view.xhtml +1 -0
  104. data/spec/innate/node/view/with_layout.xhtml +1 -0
  105. data/spec/innate/node/wrap_action_call.rb +83 -0
  106. data/spec/innate/options.rb +115 -0
  107. data/spec/innate/parameter.rb +154 -0
  108. data/spec/innate/provides.rb +99 -0
  109. data/spec/innate/provides/list.html.xhtml +1 -0
  110. data/spec/innate/provides/list.txt.xhtml +1 -0
  111. data/spec/innate/request.rb +77 -0
  112. data/spec/innate/route.rb +135 -0
  113. data/spec/innate/session.rb +54 -0
  114. data/spec/innate/state/fiber.rb +58 -0
  115. data/spec/innate/state/thread.rb +40 -0
  116. data/spec/innate/traited.rb +55 -0
  117. data/tasks/bacon.rake +66 -0
  118. data/tasks/changelog.rake +18 -0
  119. data/tasks/gem.rake +22 -0
  120. data/tasks/gem_installer.rake +76 -0
  121. data/tasks/grancher.rake +12 -0
  122. data/tasks/install_dependencies.rake +4 -0
  123. data/tasks/manifest.rake +4 -0
  124. data/tasks/rcov.rake +19 -0
  125. data/tasks/release.rake +51 -0
  126. data/tasks/reversion.rake +8 -0
  127. data/tasks/setup.rake +28 -0
  128. metadata +181 -0
@@ -0,0 +1,76 @@
1
+ Rack::Handler.register('ebb', 'Rack::Handler::Ebb')
2
+
3
+ module Innate
4
+
5
+ # Lightweight wrapper around Rack::Handler, will apply our options in a
6
+ # unified manner and deal with adapters that don't like to do what we want or
7
+ # where Rack doesn't want to take a stand.
8
+ #
9
+ # Rack handlers as of 2009.03.25:
10
+ # cgi, fastcgi, mongrel, emongrel, smongrel, webrick, lsws, scgi, thin
11
+
12
+ module Adapter
13
+ include Optioned
14
+
15
+ options.dsl do
16
+ o "IP address or hostname that we respond to - 0.0.0.0 for all",
17
+ :host, "0.0.0.0"
18
+
19
+ o "Port for the server",
20
+ :port, 7000
21
+
22
+ o "Web server to run on",
23
+ :handler, :webrick
24
+ end
25
+
26
+ # Pass given app to the Handler, handler is chosen based on config.adapter
27
+ # option.
28
+ # If there is a method named start_name_of_adapter it will be run instead
29
+ # of the default run method of the handler, this makes it easy to define
30
+ # custom startup of handlers for your server of choice.
31
+ def self.start(app, given_options = nil)
32
+ options.merge!(given_options) if given_options
33
+
34
+ handler = options[:handler].to_s.downcase
35
+ config = { :Host => options[:host], :Port => options[:port] }
36
+
37
+ Log.debug "Using #{handler}"
38
+
39
+ if respond_to?(method = "start_#{handler}")
40
+ send(method, app, config)
41
+ else
42
+ Rack::Handler.get(handler).run(app, config)
43
+ end
44
+ end
45
+
46
+ # Due to buggy autoload on Ruby 1.8 we have to require 'ebb' manually.
47
+ # This most likely happens because autoload doesn't respect the require of
48
+ # rubygems and uses the C require directly.
49
+ def self.start_ebb(app, config)
50
+ require 'ebb'
51
+ Rack::Handler.get('ebb').run(app, config)
52
+ end
53
+
54
+ # We want webrick to use our logger.
55
+ def self.start_webrick(app, config)
56
+ handler = Rack::Handler.get('webrick')
57
+ config = {
58
+ :BindAddress => config[:Host],
59
+ :Port => config[:Port],
60
+ :Logger => Log,
61
+ :AccessLog => [
62
+ [Log, ::WEBrick::AccessLog::COMMON_LOG_FORMAT],
63
+ [Log, ::WEBrick::AccessLog::REFERER_LOG_FORMAT]]
64
+ }
65
+
66
+ handler.run(app, config)
67
+ end
68
+
69
+ # Thin shouldn't give excessive output, especially not to $stdout
70
+ def self.start_thin(app, config)
71
+ handler = Rack::Handler.get('thin')
72
+ ::Thin::Logging.silent = true
73
+ handler.run(app, config)
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,134 @@
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::Cache.options 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
+ include Optioned
65
+
66
+ options.dsl do
67
+ o "Assign a cache to each of these names on Innate::Cache::setup",
68
+ :names, [:session]
69
+
70
+ default "If no option for the cache name exists, fall back to this",
71
+ Innate::Cache::Memory
72
+ end
73
+
74
+ attr_reader :name, :instance
75
+
76
+ def initialize(name, klass = nil)
77
+ @name = name.to_s.dup.freeze
78
+
79
+ klass ||= options[@name.to_sym]
80
+ @instance = klass.new
81
+
82
+ @instance.cache_setup(
83
+ ENV['HOSTNAME'],
84
+ ENV['USER'],
85
+ 'pristine',
86
+ @name
87
+ )
88
+ end
89
+
90
+ # Add all caches from the options.
91
+ #
92
+ # @see Innate::setup_dependencies
93
+ # @api stable
94
+ # @return [Array] names of caches initialized
95
+ # @author manveru
96
+ def self.setup
97
+ options.names.each{|name| add(name) }
98
+ end
99
+
100
+ # Add accessors for cache
101
+ #
102
+ # @param [Cache] cache
103
+ def self.register(cache)
104
+ key = cache.name
105
+ source = "def self.%s() @%s; end
106
+ def self.%s=(o) @%s = o; end" % [key, key, key, key]
107
+ self.class_eval(source, __FILE__, __LINE__)
108
+
109
+ self.send("#{key}=", cache)
110
+ end
111
+
112
+ def self.add(*names)
113
+ names.each{|name| register(new(name)) }
114
+ end
115
+
116
+ def clear
117
+ instance.cache_clear
118
+ end
119
+
120
+ def delete(*keys)
121
+ instance.cache_delete(*keys)
122
+ end
123
+
124
+ def fetch(key, default = nil)
125
+ instance.cache_fetch(key, default)
126
+ end
127
+ alias [] fetch
128
+
129
+ def store(key, value, options = {})
130
+ instance.cache_store(key, value, options)
131
+ end
132
+ alias []= store
133
+ end
134
+ end
@@ -0,0 +1,128 @@
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
+ # @param [String #to_s] hostname the hostname of the machine
33
+ # @param [String #to_s] username user executing the process
34
+ # @param [String #to_s] appname identifier for the application
35
+ # @param [String #to_s] cachename namespace, like 'session' or 'action'
36
+ # @author manveru
37
+ def cache_setup(hostname, username, appname, cachename)
38
+ end
39
+
40
+ # Remove all key/value pairs from the cache.
41
+ # Should behave as if #delete had been called with all +keys+ as argument.
42
+ #
43
+ # @author manveru
44
+ def cache_clear
45
+ clear
46
+ end
47
+
48
+ # Remove the corresponding key/value pair for each key passed.
49
+ # If removing is not an option it should set the corresponding value to nil.
50
+ #
51
+ # If only one key was deleted, answer with the corresponding value.
52
+ # If multiple keys were deleted, answer with an Array containing the values.
53
+ #
54
+ # NOTE: Due to differences in the underlying implementation in the
55
+ # caches, some may not return the deleted value as it would mean
56
+ # another lookup before deletion. This is the case for caches on
57
+ # memcached or any database system.
58
+ #
59
+ # @param [Object] key the key for the value to delete
60
+ # @param [Object] keys any other keys to delete as well
61
+ # @return [Object Array nil]
62
+ # @author manveru
63
+ def cache_delete(key, *keys)
64
+ if keys.empty?
65
+ if value = yield(key)
66
+ value[:value]
67
+ end
68
+ else
69
+ [key, *keys].map{|k| cache_delete(k) }
70
+ end
71
+ end
72
+
73
+ # Answer with the value associated with the +key+, +nil+ if not found or
74
+ # expired.
75
+ #
76
+ # @param [Object] key the key for which to fetch the value
77
+ # @param [Object] default will return this if no value was found
78
+ # @return [Object]
79
+ # @see Innate::Cache#fetch Innate::Cache#[]
80
+ # @author manveru
81
+ def cache_fetch(key, default = nil)
82
+ value = default
83
+
84
+ if entry = yield(key)
85
+ if expires = entry[:expires]
86
+ if expires > Time.now
87
+ value = entry[:value]
88
+ else
89
+ cache_delete(key)
90
+ end
91
+ else
92
+ value = entry[:value]
93
+ end
94
+ end
95
+
96
+ return value
97
+ end
98
+
99
+ # Set +key+ to +value+.
100
+ #
101
+ # +options+ may be one of:
102
+ # :ttl => time to live in seconds if given in Numeric
103
+ # infinite or maximum if not given
104
+ #
105
+ # Usage:
106
+ # Cache.value.store(:num, 3, :ttl => 20)
107
+ # Cache.value.fetch(:num) # => 3
108
+ # sleep 21
109
+ # Cache.value.fetch(:num) # => nil
110
+ #
111
+ # @param [Object] key the value is stored with this key
112
+ # @param [Object] value the key points to this value
113
+ # @param [Hash] options for now, only :ttl => Fixnum is used.
114
+ # @see Innate::Cache#store Innate::Cache#[]=
115
+ # @author manveru
116
+ def cache_store(key, value, options = {})
117
+ ttl = options[:ttl]
118
+
119
+ value_hash = {:value => value}
120
+ value_hash[:expires] = Time.now + ttl if ttl
121
+
122
+ yield(key, value_hash)
123
+
124
+ return value
125
+ end
126
+ end
127
+ end
128
+ 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,41 @@
1
+ module Innate
2
+ class Cache
3
+
4
+ # Used by caches that serialize their contents to the filesystem.
5
+ module FileBased
6
+ attr_reader :filename
7
+
8
+ def cache_setup(*args)
9
+ @prefix = args.compact.join('-')
10
+
11
+ @dir = File.join(Dir.tmpdir, self.class::DIR)
12
+ FileUtils.mkdir_p(@dir)
13
+
14
+ @filename = File.join(@dir, @prefix + self.class::EXT)
15
+ @store = self.class::STORE.new(@filename)
16
+ end
17
+
18
+ def cache_clear
19
+ FileUtils.mkdir_p(@dir)
20
+ FileUtils.rm_f(@filename)
21
+ @store = self.class::STORE.new(@filename)
22
+ end
23
+
24
+ def cache_store(*args)
25
+ super{|key, value| transaction{|store| store[key] = value } }
26
+ end
27
+
28
+ def cache_fetch(*args)
29
+ super{|key| transaction{|store| store[key] } }
30
+ end
31
+
32
+ def cache_delete(*args)
33
+ super{|key| transaction{|store| store.delete(key) } }
34
+ end
35
+
36
+ def transaction(&block)
37
+ Innate.sync{ @store.transaction(&block) }
38
+ end
39
+ end
40
+ end
41
+ 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