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,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,152 @@
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
+ def self.included(into)
9
+ into.extend(self)
10
+ end
11
+
12
+ # Renders the full action in the way a real request would.
13
+ #
14
+ # Please be aware that, if this is the first request from a client, you
15
+ # will not have access to the session in the action being rendered, as no
16
+ # actual session has been put into place yet.
17
+ #
18
+ # It should work as expected on any subsequent requests.
19
+ #
20
+ # As usual, patches welcome.
21
+ #
22
+ # @example usage
23
+ #
24
+ # render_full('/blog/article/1')
25
+ # render_full('/blog/article/1', :lang => :de)
26
+ #
27
+ # Please note that you have to give the full path in the same way you'd
28
+ # do in a direct request with curl or a browser.
29
+ #
30
+ # @api external
31
+ # @see Mock.session
32
+ # @author manveru
33
+ def render_full(path, query = {})
34
+ uri = URI(path.to_s)
35
+ uri.query = Rack::Utils.build_query(query)
36
+
37
+ if cookie = request.env['HTTP_COOKIE']
38
+ Mock.session do |mock|
39
+ mock.cookie = cookie
40
+ return mock.get(uri.to_s).body
41
+ end
42
+ else
43
+ Mock.get(uri.to_s).body
44
+ end
45
+ end
46
+
47
+ # Renders an action without any layout.
48
+ # You can further tweak the action to be rendered by passing a block.
49
+ #
50
+ # @example usage
51
+ #
52
+ # render_partial(:index)
53
+ # render_partial(:index, :title => :foo)
54
+ #
55
+ # Please note that you only have to supply the action name, if your
56
+ # action requires arguments then you have to pass a name suitable for
57
+ # that.
58
+ #
59
+ # @example usage with action that requires arguments
60
+ #
61
+ # # requires two arguments
62
+ # def foo(a, b)
63
+ # end
64
+ #
65
+ # # pass two suitable arguments
66
+ # render_partial('foo/1/2')
67
+ #
68
+ # @api external
69
+ # @see render_custom
70
+ # @author manveru
71
+ def render_partial(action_name, variables = {})
72
+ render_custom(action_name, variables) do |action|
73
+ action.layout = nil
74
+ yield(action) if block_given?
75
+ end
76
+ end
77
+
78
+ # Renders an action view, doesn't execute any methods and won't wrap it
79
+ # into a layout.
80
+ # You can further tweak the action to be rendered by passing a block.
81
+ #
82
+ # @example usage
83
+ #
84
+ # render_view(:index)
85
+ # render_view(:index, :title => :foo)
86
+ #
87
+ # @api external
88
+ # @see render_custom
89
+ # @author manveru
90
+ def render_view(action_name, variables = {})
91
+ render_custom(action_name, variables) do |action|
92
+ action.layout = nil
93
+ action.method = nil
94
+ yield(action) if block_given?
95
+ end
96
+ end
97
+
98
+ # Use the given file as a template and render it in the same scope as
99
+ # the current action.
100
+ # The +filename+ may be an absolute path or relative to the process
101
+ # working directory.
102
+ #
103
+ # @example usage
104
+ #
105
+ # path = '/home/manveru/example/app/todo/view/index.xhtml'
106
+ # render_file(path)
107
+ # render_file(path, :title => :foo)
108
+ #
109
+ # Ramaze will emit a warning if you try to render an Action without a
110
+ # method or view template, but will still try to render it.
111
+ # The usual {Action#valid?} doesn't apply here, as sometimes you just
112
+ # cannot have a method associated with a template.
113
+ #
114
+ # @api external
115
+ # @see render_custom
116
+ # @author manveru
117
+ def render_file(filename, variables = {})
118
+ action = Action.create(:view => filename)
119
+ action.sync_variables(self.action)
120
+
121
+ action.node = self.class
122
+ action.engine = self.action.engine
123
+ action.instance = action.node.new
124
+ action.variables = variables.dup
125
+
126
+ yield(action) if block_given?
127
+
128
+ valid_action = action.view || action.method
129
+ Log.warn("Empty action: %p" % [action]) unless valid_action
130
+ action.render
131
+ end
132
+
133
+ # @api internal
134
+ # @author manveru
135
+ def render_custom(action_name, variables = {})
136
+ unless action = resolve(action_name.to_s)
137
+ raise(ArgumentError, "No Action %p on #{self}" % [action_name])
138
+ end
139
+
140
+ action.sync_variables(self.action)
141
+ action.instance = action.node.new
142
+ action.variables = action.variables.merge(variables)
143
+
144
+ yield(action) if block_given?
145
+
146
+ valid_action = action.view || action.method
147
+ Log.warn("Empty action: %p" % [action]) unless valid_action
148
+ action.render
149
+ end
150
+ end
151
+ end
152
+ 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