innate 2009.04

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/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,54 @@
1
+ autoload(:CGI, 'cgi') # in case you want to use html_unescape
2
+
3
+ module Innate
4
+
5
+ # Shortcuts to some CGI methods
6
+
7
+ module Helper
8
+ module CGI
9
+ module_function
10
+
11
+ # Shortcut for Rack::Utils.escape
12
+ #
13
+ # @param [#to_s] input
14
+ # @return [String] URI-encoded representation of +input+
15
+ def url_encode(input)
16
+ Rack::Utils.escape(input.to_s)
17
+ end
18
+ alias u url_encode
19
+
20
+ # Shortcut for Rack::Utils.unescape
21
+ #
22
+ # @param [#to_s] input
23
+ # @return [String] URI-decoded representation of +input+
24
+ def url_decode(input)
25
+ Rack::Utils.unescape(input.to_s)
26
+ end
27
+
28
+ # Shortcut for Rack::Utils.escape_html
29
+ #
30
+ # @param [#to_s] input
31
+ # @return [String]
32
+ def html_escape(input)
33
+ Rack::Utils.escape_html(input.to_s)
34
+ end
35
+
36
+ # Shortcut for CGI.unescapeHTML
37
+ #
38
+ # @param [#to_s] input
39
+ # @return [String]
40
+ def html_unescape(input)
41
+ ::CGI.unescapeHTML(input.to_s)
42
+ end
43
+
44
+ # safely escape all HTML and code
45
+ def html_and_code_escape(input)
46
+ Rack::Utils.escape_html(input.to_s).gsub(/#([{@$]@?)/, '#\1')
47
+ end
48
+ alias h html_and_code_escape
49
+
50
+ # aliases are ignored by module_function...
51
+ module_function :u, :h
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,36 @@
1
+ module Innate
2
+ module Helper
3
+ # Simple access to session.flash.
4
+ #
5
+ # Flash is a mechanism using sessions to provide a rotating holder of
6
+ # key/value pairs.
7
+ #
8
+ # Every request that is made will rotate one step, dropping contents stored
9
+ # two requests ago.
10
+ #
11
+ # The purpose of this class is to provide an easy way of setting/retrieving
12
+ # from the current flash.
13
+ #
14
+ # Flash is a way to keep a temporary pairs of keys and values for the duration
15
+ # of two requests, the current and following.
16
+ #
17
+ # Very vague Example:
18
+ #
19
+ # On the first request, for example on registering:
20
+ #
21
+ # flash[:error] = "You should reconsider your username, it's taken already"
22
+ # redirect R(self, :register)
23
+ #
24
+ # This is the request from the redirect:
25
+ #
26
+ # do_stuff if flash[:error]
27
+ #
28
+ # On the request after this, flash[:error] is gone.
29
+ module Flash
30
+ # Just for convenience
31
+ def flash
32
+ session.flash
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,94 @@
1
+ module Innate
2
+ module Helper
3
+ module Link
4
+ def self.included(into)
5
+ into.extend(self)
6
+ end
7
+
8
+ # Provide the path to given Node and actions.
9
+ # Escapes GET parameters.
10
+ #
11
+ # Usage, mapping is Pages => '/', Users => '/users':
12
+ #
13
+ # Pages.r # => URI('/')
14
+ # Pages.r(:foo) # => URI('/foo')
15
+ # Pages.r(:foo, :bar) # => URI('/foo/bar')
16
+ # Pages.r(:foo, :a => :b) # => URI('/foo?a=b')
17
+ # Pages.r(:foo, :bar, :a => :b) # => URI('/foo/bar?a=b')
18
+ #
19
+ # Users.r # => URI('/users/')
20
+ # Users.r(:foo) # => URI('/users/foo')
21
+ # Users.r(:foo, :bar) # => URI('/users/foo/bar')
22
+ # Users.r(:foo, :a => :b) # => URI('/users/foo?a=b')
23
+ # Users.r(:foo, :bar, :a => :b) # => URI('/users/foo/bar?a=b')
24
+ #
25
+ # @return [URI] to the location
26
+ def route(name = '/', *args)
27
+ hash = {}
28
+ hashes, names = args.partition{|arg| arg.respond_to?(:merge!) }
29
+ hashes.each{|to_merge| hash.merge!(to_merge) }
30
+
31
+ escape = Rack::Utils.method(:escape)
32
+ location = route_location(self)
33
+ front = Array[location, name, *names.map{|n| escape[n]}].join('/').squeeze('/')
34
+
35
+ return URI(front) if hash.empty?
36
+
37
+ query = hash.map{|k, v| "#{escape[k]}=#{escape[v]}" }.join(';')
38
+ URI("#{front}?#{query}")
39
+ end
40
+ alias r route
41
+
42
+ def route_location(klass)
43
+ prefix = Innate.options.prefix
44
+ location = Innate.to(klass) || Innate.to(klass.class)
45
+ [prefix, location].join('/')
46
+ end
47
+
48
+ # Create a route to the currently active Node.
49
+ #
50
+ # This method is mostly here in case you include this helper elsewhere
51
+ # and don't want (or can't) type SomeNode.r all the time.
52
+ #
53
+ # The usage is identical with {route}.
54
+ #
55
+ # @param [#to_s] name
56
+ # @return [URI] to the location
57
+ # @see Ramaze::Helper::Link#route
58
+ # @author manveru
59
+ def route_self(name = '/', *args)
60
+ Current.action.node.route(name, *args)
61
+ end
62
+ alias rs route_self
63
+
64
+ # Create a link tag
65
+ #
66
+ # Usage, given Wiki is mapped to `/wiki`:
67
+ #
68
+ # Wiki.a(:home) # => '<a href="/wiki/home">home</a>'
69
+ # Wiki.a('home', :home) # => '<a href="/wiki/home">home</a>'
70
+ # Wiki.a('home', :/) # => '<a href="/wiki/">home</a>'
71
+ # Wiki.a('foo', :/, :foo => :bar) # => '<a href="/wiki/?foo=bar">foo</a>'
72
+ # Wiki.a('example', 'http://example.com')
73
+ # # => '<a href="http://example.com">example</a>'
74
+ #
75
+ # @return [String]
76
+ def anchor(text, *args)
77
+ case first = (args.first || text)
78
+ when URI
79
+ href = first.to_s
80
+ when /^\w+:\/\//
81
+ uri = URI(first)
82
+ uri.query = Rack::Utils.escape_html(uri.query)
83
+ href = uri.to_s
84
+ else
85
+ href = args.empty? ? r(text) : r(*args)
86
+ end
87
+
88
+ text = Rack::Utils.escape_html(text)
89
+ %(<a href="#{href}">#{text}</a>)
90
+ end
91
+ alias a anchor
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,85 @@
1
+ module Innate
2
+ module Helper
3
+ module Redirect
4
+ def respond(body, status = 200, header = {})
5
+ response.write body
6
+ response.status = status
7
+ header['Content-Type'] ||= 'text/html'
8
+ header.each{|k,v| response[k] = v }
9
+
10
+ throw(:respond, response)
11
+ end
12
+
13
+ def respond!(body, status = 200, header = {})
14
+ header['Content-Type'] ||= 'text/html'
15
+ throw(:respond, Response.new(body, status, header))
16
+ end
17
+
18
+ # +target+ should be anything responding to #to_s.
19
+ # To check or modify the URI the redirect will go to you may pass a
20
+ # block, the result value of the block is ignored:
21
+ #
22
+ # redirect("/"){|uri| uri.scheme = 'http' }
23
+ # redirect("/"){|uri| uri.host = 'secure.com' if uri.scheme =~ /s/ }
24
+ #
25
+ # +options+ may contain:
26
+ #
27
+ # :scheme => "http" | "https" | "ftp" | ...
28
+ # :host => "localhost" | "foo.com" | "123.123.123.123" | ...
29
+ # :port => 7000 | "80" | 80 | ...
30
+ #
31
+ # :status => 302 | 300 | 303 | ...
32
+ # :body => "This is a redirect, hold on while we teleport" | ...
33
+ #
34
+ # :raw! => true | false | nil | ...
35
+ #
36
+ # Note that all options are optional and you may just pass a +target+.
37
+
38
+ def redirect(target, options = {})
39
+ target = target.to_s
40
+
41
+ case target
42
+ when /^http/, /^\//
43
+ uri = URI(target)
44
+ else
45
+ uri = URI("/#{target}")
46
+ end
47
+
48
+ uri.scheme ||= options[:scheme] || request.scheme
49
+ uri.host ||= options[:host] || request.host
50
+ uri.port ||= options[:port] || request.port
51
+
52
+ uri = URI(uri.to_s)
53
+
54
+ yield(uri) if block_given?
55
+
56
+ raw_redirect(uri, options)
57
+ end
58
+
59
+ def raw_redirect(target, options = {}, &block)
60
+ header = response.header.merge('Location' => target.to_s)
61
+ status = options[:status] || 302
62
+ body = options[:body] || redirect_body(target)
63
+
64
+ Log.debug "Redirect to: #{target}"
65
+ throw(:redirect, Response.new(body, status, header, &block))
66
+ end
67
+
68
+ def redirect_body(target)
69
+ "You are being redirected, please follow this link to: " +
70
+ "<a href='#{target}'>#{h target}</a>!"
71
+ end
72
+
73
+ def redirect_referrer(fallback = '/')
74
+ if referer = request.referer and url = request.url
75
+ referer_uri, request_uri = URI(referer), URI(url)
76
+
77
+ redirect(referer) unless referer_uri == request_uri
78
+ end
79
+
80
+ redirect(fallback)
81
+ end
82
+ alias redirect_referer redirect_referrer
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,87 @@
1
+ module Innate
2
+ module Helper
3
+ module Render
4
+ # Enables you to simply call:
5
+ #
6
+ # @example of added functionality
7
+ # YourController.render_partial(:foo, :x => 42)
8
+ #
9
+ def self.included(into)
10
+ into.extend(self)
11
+ end
12
+
13
+ # Renders the full action in the way a real request would.
14
+ #
15
+ # Please be aware that, if this is the first request from a client, you
16
+ # will not have access to the session in the action being rendered, as no
17
+ # actual session has been put into place yet.
18
+ #
19
+ # It should work as expected on any subsequent requests.
20
+ #
21
+ # As usual, patches welcome.
22
+ #
23
+ # @api external
24
+ # @see Mock.session
25
+ # @author manveru
26
+ def render_full(path, query = {})
27
+ uri = URI(path.to_s)
28
+ uri.query = Rack::Utils.build_query(query)
29
+
30
+ if cookie = request.env['HTTP_COOKIE']
31
+ Mock.session do |mock|
32
+ mock.cookie = cookie
33
+ return mock.get(uri.to_s).body
34
+ end
35
+ else
36
+ Mock.get(uri.to_s).body
37
+ end
38
+ end
39
+
40
+ # Renders an action without any layout.
41
+ # You can further tweak the action to be rendered by passing a block.
42
+ #
43
+ # @api external
44
+ # @see render_custom
45
+ # @author manveru
46
+ def render_partial(action_name, variables = {})
47
+ render_custom(action_name, variables) do |action|
48
+ action.layout = nil
49
+ yield(action) if block_given?
50
+ end
51
+ end
52
+
53
+ # Renders an action view, doesn't execute any methods and won't wrap it
54
+ # into a layout.
55
+ # You can further tweak the action to be rendered by passing a block.
56
+ #
57
+ # @api external
58
+ # @see render_custom
59
+ # @author manveru
60
+ def render_view(action_name, variables = {})
61
+ render_custom(action_name, variables) do |action|
62
+ action.layout = nil
63
+ action.method = nil
64
+ yield(action) if block_given?
65
+ end
66
+ end
67
+
68
+ def render_custom(action_name, variables = {})
69
+ unless action = resolve(action_name.to_s)
70
+ raise(ArgumentError, "No Action %p on #{self}" % action_name)
71
+ end
72
+
73
+ action.sync_variables(self.action)
74
+ action.instance = action.node.new
75
+ action.variables = action.variables.merge(variables)
76
+
77
+ yield(action) if block_given?
78
+
79
+ if action.valid?
80
+ action.render
81
+ else
82
+ Log.warn("Invalid action: %p" % action)
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,26 @@
1
+ module Innate
2
+ module Helper
3
+ module SendFile
4
+ # Not optimally performing but convenient way to send files by their
5
+ # filename.
6
+ #
7
+ # I think we should remove this from the default helpers and move it into
8
+ # Ramaze, the functionality is almost never used, the naming is ambigous,
9
+ # and it doesn't use the send_file capabilities of frontend servers.
10
+ #
11
+ # So for now, I'll mark it for deprecation
12
+ def send_file(filename, content_type = nil, content_disposition = nil)
13
+ content_type ||= Rack::Mime.mime_type(::File.extname(filename))
14
+ content_disposition ||= File.basename(filename)
15
+
16
+ response.body = ::File.readlines(filename, 'rb')
17
+ response['Content-Length'] = ::File.size(filename).to_s
18
+ response['Content-Type'] = content_type
19
+ response['Content-Disposition'] = content_disposition
20
+ response.status = 200
21
+
22
+ throw(:respond, response)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,20 @@
1
+ require 'innate/log/hub'
2
+ require 'innate/log/color_formatter'
3
+
4
+ module Innate
5
+ logdev = $stderr
6
+ logger = Logger.new(logdev)
7
+
8
+ if Logger::ColorFormatter.color?(logdev)
9
+ begin
10
+ require 'win32console' if RUBY_PLATFORM =~ /win32/i
11
+
12
+ logger.formatter = Logger::ColorFormatter.new
13
+
14
+ rescue LoadError
15
+ logger.debug "For colors on windows, please `gem install win32console`"
16
+ end
17
+ end
18
+
19
+ Log = LogHub.new(logger)
20
+ end
@@ -0,0 +1,43 @@
1
+ class Logger
2
+ # Extended Formatter that supports ANSI colors.
3
+ class ColorFormatter < Formatter
4
+ LEVEL_COLOR = {
5
+ 'DEBUG' => :blue,
6
+ 'INFO' => :white,
7
+ 'WARN' => :yellow,
8
+ 'ERROR' => :red,
9
+ 'FATAL' => :red,
10
+ 'UNKNOWN' => :green,
11
+ }
12
+
13
+ COLOR_CODE = {
14
+ :reset => 0, :bold => 1, :dark => 2, :underline => 4, :blink => 5,
15
+ :negative => 7, :black => 30, :red => 31, :green => 32, :yellow => 33,
16
+ :blue => 34, :magenta => 35, :cyan => 36, :white => 37,
17
+ }
18
+
19
+ FORMAT_TIME = "%Y-%m-%d %H:%M:%S"
20
+ FORMAT_LINE = "%s [%s $%d] %5s | %s: %s\n"
21
+
22
+ def call(severity, time, program, message)
23
+ hint = severity[0,1]
24
+ time = format_time(time)
25
+ pid = $$
26
+ string = colorize(msg2str(message), severity)
27
+
28
+ FORMAT_LINE % [hint, time, pid, severity, program, string]
29
+ end
30
+
31
+ def format_time(time)
32
+ time.strftime(FORMAT_TIME)
33
+ end
34
+
35
+ def colorize(string, severity)
36
+ "\e[#{COLOR_CODE[LEVEL_COLOR[severity]]}m#{string}\e[0m"
37
+ end
38
+
39
+ def self.color?(logdev)
40
+ logdev.respond_to?(:tty?) and logdev.tty?
41
+ end
42
+ end
43
+ end