rjspotter-innate 2009.06.29

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 (128) hide show
  1. data/AUTHORS +10 -0
  2. data/CHANGELOG +3261 -0
  3. data/COPYING +18 -0
  4. data/MANIFEST +127 -0
  5. data/README.md +563 -0
  6. data/Rakefile +39 -0
  7. data/example/app/retro_games.rb +60 -0
  8. data/example/app/todo/layout/default.xhtml +11 -0
  9. data/example/app/todo/spec/todo.rb +63 -0
  10. data/example/app/todo/start.rb +51 -0
  11. data/example/app/todo/view/index.xhtml +39 -0
  12. data/example/app/whywiki_erb/layout/wiki.html.erb +15 -0
  13. data/example/app/whywiki_erb/spec/wiki.rb +19 -0
  14. data/example/app/whywiki_erb/start.rb +42 -0
  15. data/example/app/whywiki_erb/view/edit.erb +6 -0
  16. data/example/app/whywiki_erb/view/index.erb +12 -0
  17. data/example/custom_middleware.rb +35 -0
  18. data/example/hello.rb +11 -0
  19. data/example/howto_spec.rb +35 -0
  20. data/example/link.rb +27 -0
  21. data/example/provides.rb +31 -0
  22. data/example/session.rb +38 -0
  23. data/innate.gemspec +41 -0
  24. data/lib/innate.rb +269 -0
  25. data/lib/innate/action.rb +137 -0
  26. data/lib/innate/adapter.rb +76 -0
  27. data/lib/innate/cache.rb +134 -0
  28. data/lib/innate/cache/api.rb +128 -0
  29. data/lib/innate/cache/drb.rb +58 -0
  30. data/lib/innate/cache/file_based.rb +44 -0
  31. data/lib/innate/cache/marshal.rb +20 -0
  32. data/lib/innate/cache/memory.rb +21 -0
  33. data/lib/innate/cache/yaml.rb +20 -0
  34. data/lib/innate/current.rb +35 -0
  35. data/lib/innate/dynamap.rb +96 -0
  36. data/lib/innate/helper.rb +185 -0
  37. data/lib/innate/helper/aspect.rb +124 -0
  38. data/lib/innate/helper/cgi.rb +54 -0
  39. data/lib/innate/helper/flash.rb +36 -0
  40. data/lib/innate/helper/link.rb +94 -0
  41. data/lib/innate/helper/redirect.rb +85 -0
  42. data/lib/innate/helper/render.rb +152 -0
  43. data/lib/innate/helper/send_file.rb +26 -0
  44. data/lib/innate/log.rb +20 -0
  45. data/lib/innate/log/color_formatter.rb +49 -0
  46. data/lib/innate/log/hub.rb +77 -0
  47. data/lib/innate/middleware_compiler.rb +65 -0
  48. data/lib/innate/mock.rb +49 -0
  49. data/lib/innate/node.rb +1029 -0
  50. data/lib/innate/options.rb +37 -0
  51. data/lib/innate/options/dsl.rb +205 -0
  52. data/lib/innate/options/stub.rb +7 -0
  53. data/lib/innate/request.rb +141 -0
  54. data/lib/innate/response.rb +24 -0
  55. data/lib/innate/route.rb +114 -0
  56. data/lib/innate/session.rb +133 -0
  57. data/lib/innate/session/flash.rb +94 -0
  58. data/lib/innate/spec.rb +1 -0
  59. data/lib/innate/spec/bacon.rb +28 -0
  60. data/lib/innate/state.rb +26 -0
  61. data/lib/innate/state/accessor.rb +130 -0
  62. data/lib/innate/traited.rb +90 -0
  63. data/lib/innate/trinity.rb +18 -0
  64. data/lib/innate/version.rb +3 -0
  65. data/lib/innate/view.rb +97 -0
  66. data/lib/innate/view/erb.rb +14 -0
  67. data/lib/innate/view/etanni.rb +33 -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 +121 -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 +115 -0
  86. data/spec/innate/helper/link.rb +139 -0
  87. data/spec/innate/helper/redirect.rb +171 -0
  88. data/spec/innate/helper/render.rb +165 -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/modes.rb +61 -0
  98. data/spec/innate/node/mapping.rb +37 -0
  99. data/spec/innate/node/node.rb +135 -0
  100. data/spec/innate/node/resolve.rb +82 -0
  101. data/spec/innate/node/view/another_layout/another_layout.xhtml +3 -0
  102. data/spec/innate/node/view/bar.xhtml +1 -0
  103. data/spec/innate/node/view/foo.html.xhtml +1 -0
  104. data/spec/innate/node/view/only_view.xhtml +1 -0
  105. data/spec/innate/node/view/with_layout.xhtml +1 -0
  106. data/spec/innate/node/wrap_action_call.rb +83 -0
  107. data/spec/innate/options.rb +123 -0
  108. data/spec/innate/parameter.rb +154 -0
  109. data/spec/innate/provides.rb +99 -0
  110. data/spec/innate/provides/list.html.xhtml +1 -0
  111. data/spec/innate/provides/list.txt.xhtml +1 -0
  112. data/spec/innate/request.rb +79 -0
  113. data/spec/innate/route.rb +135 -0
  114. data/spec/innate/session.rb +58 -0
  115. data/spec/innate/traited.rb +55 -0
  116. data/tasks/authors.rake +30 -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_setup.rake +99 -0
  121. data/tasks/grancher.rake +12 -0
  122. data/tasks/manifest.rake +4 -0
  123. data/tasks/rcov.rake +19 -0
  124. data/tasks/release.rake +53 -0
  125. data/tasks/reversion.rake +8 -0
  126. data/tasks/setup.rake +6 -0
  127. data/tasks/ycov.rake +84 -0
  128. metadata +218 -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, :view]
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 usage of DRb server
13
+ # require 'drb'
14
+ #
15
+ # URI = "druby://127.0.0.1:9069"
16
+ # CACHE = {}
17
+ #
18
+ # $SAFE = 1 # disable eval and friends
19
+ #
20
+ # DRb.start_service(URI, CACHE)
21
+ # DRb.thread.join
22
+ #
23
+ # Please note that on some Ruby implementations, access to Hash is not
24
+ # atomic and you might need to lock around access to avoid race conditions.
25
+ #
26
+ # @example for all caches
27
+ # Innate.options.cache.default = Innate::Cache::DRb
28
+ #
29
+ # @example for sessions only
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,44 @@
1
+ module Innate
2
+ class Cache
3
+
4
+ # Used by caches that serialize their contents to the filesystem.
5
+ # Right now we do not lock around write access to the file outside of the
6
+ # process, that means that all FileBased caches are not safe for use if you
7
+ # need more than one instance of your application.
8
+ module FileBased
9
+ attr_reader :filename
10
+
11
+ def cache_setup(*args)
12
+ @prefix = args.compact.join('-')
13
+
14
+ @dir = File.join(Dir.tmpdir, self.class::DIR)
15
+ FileUtils.mkdir_p(@dir)
16
+
17
+ @filename = File.join(@dir, @prefix + self.class::EXT)
18
+ @store = self.class::STORE.new(@filename)
19
+ end
20
+
21
+ def cache_clear
22
+ FileUtils.mkdir_p(@dir)
23
+ FileUtils.rm_f(@filename)
24
+ @store = self.class::STORE.new(@filename)
25
+ end
26
+
27
+ def cache_store(*args)
28
+ super{|key, value| transaction{|store| store[key] = value } }
29
+ end
30
+
31
+ def cache_fetch(*args)
32
+ super{|key| transaction{|store| store[key] } }
33
+ end
34
+
35
+ def cache_delete(*args)
36
+ super{|key| transaction{|store| store.delete(key) } }
37
+ end
38
+
39
+ def transaction(&block)
40
+ Innate.sync{ @store.transaction(&block) }
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,20 @@
1
+ require 'pstore'
2
+
3
+ module Innate
4
+ class Cache
5
+ # Keeps every cache in a separate file like this:
6
+ # /tmp/innate-cache-marshal/delta-manveru-session.marshal
7
+ #
8
+ # The Marshal cache is not safe for use between multiple processes, it is
9
+ # also slow compared to other caches, so generally the use of it is
10
+ # discouraged.
11
+ class Marshal
12
+ include Cache::API
13
+ include Cache::FileBased
14
+
15
+ STORE = ::PStore
16
+ DIR = 'innate-cache-marshal'
17
+ EXT = '.marshal'
18
+ end
19
+ end
20
+ end